HTTP协议

文档

HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待直到收到服务器端响应。HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。尽管通常基于 TCP/IP 层,但它可以在任何可靠的传输层上使用,也就是说,该协议不会像 UDP 那样静默的丢失消息。RUDP——作为 UDP 的可靠化升级版本——是一种合适的替代选择。

1. 概述

HTTP是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础,是一种 client-server 协议,也就是说,请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通常是由不同的子文档拼接而成的,像是文本、布局描述、图片、视频、脚本等等。

客户端和服务端通过交换各自的消息(与数据流正好相反)进行交互。由像浏览器这样的客户端发出的消息叫做 requests,被服务端响应的消息叫做 responses。

HTTP被设计于20世纪90年代初期,是一种可扩展的协议。它是应用层的协议,通过TCP,或者是TLS-加密的TCP连接来发送,理论上任何可靠的传输协议都可以使用。因为其良好的扩展性,时至今日,它不仅被用来传输超文本文档,还用来传输图片、视频或者向服务器发送如HTML表单这样的信息。HTTP还可以根据网页需求,仅获取部分Web文档内容更新网页。

2. 典型的http会话

在像 HTTP 这样的Client-Server(客户端-服务器)协议中,会话分为三个阶段:

  1. 客户端建立一条 TCP 连接(如果传输层不是 TCP,也可以是其他适合的连接)。
  2. 客户端发送请求并等待应答。
  3. 服务器处理请求并送回应答,回应包括一个状态码和对应的数据。

从 HTTP/1.1 开始,连接在完成第三阶段后不再关闭,客户端可以再次发起新的请求。这意味着第二步和第三步可以连续进行数次。

3. 特点

  1. http是简单的

虽然下一代HTTP/2协议将HTTP消息封装到了帧(frames)中,HTTP大体上还是被设计得简单易读。HTTP报文能够被人读懂,还允许简单测试,降低了门槛,对新人很友好。

  1. HTTP 是可扩展的

在 HTTP/1.0 中出现的 HTTP headers 让协议扩展变得非常容易。只要服务端和客户端就新 headers 达成语义一致,新功能就可以被轻松加入进来。

  1. HTTP 是无状态,有会话的

HTTP是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用HTTP的头部扩展,HTTP Cookies就可以解决这个问题。把Cookies添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。

注意,HTTP本质是无状态的,使用Cookies可以创建有状态的会话。

  1. HTTP 和连接

一个连接是由传输层来控制的,这从根本上不属于HTTP的范围。HTTP并不需要其底层的传输层协议是面向连接的,只需要它是可靠的,或不丢失消息的(至少返回错误)。在互联网中,有两个最常用的传输层协议:TCP是可靠的,而UDP不是。因此,HTTP依赖于面向连接的TCP进行消息传递,但连接并不是必须的。

在客户端(通常指浏览器)与服务器能够交互(客户端发起请求,服务器返回响应)之前,必须在这两者间建立一个 TCP 链接,打开一个 TCP 连接需要多次往返交换消息(因此耗时)。HTTP/1.0 默认为每一对 HTTP 请求/响应都打开一个单独的 TCP 连接。当需要连续发起多个请求时,这种模式比多个请求共享同一个 TCP 链接更低效。

为了减轻这些缺陷,HTTP/1.1引入了流水线(被证明难以实现)和持久连接的概念:底层的TCP连接可以通过Connection头部来被部分控制。HTTP/2则发展得更远,通过在一个连接复用消息的方式来让这个连接始终保持为暖连接。

为了更好的适合HTTP,设计一种更好传输协议的进程一直在进行。Google就研发了一种以UDP为基础,能提供更可靠更高效的传输协议QUIC。

4. http报文

HTTP/1.1以及更早的HTTP协议报文都是语义可读的。在HTTP/2中,这些报文被嵌入到了一个新的二进制结构,帧。帧允许实现很多优化,比如报文头部的压缩和复用。即使只有原始HTTP报文的一部分以HTTP/2发送出来,每条报文的语义依旧不变,客户端会重组原始HTTP/1.1请求。因此用HTTP/1.1格式来理解HTTP/2报文仍旧有效。

有两种HTTP报文的类型,请求与响应,每种都有其特定的格式。

4.1 请求(request)

HTTP请求的一个例子

请求由以下元素组成:

  • 一个HTTP的method,经常是由一个动词像GET, POST 或者一个名词像OPTIONS,HEAD来定义客户端的动作行为。通常客户端的操作都是获取资源(GET方法)或者发送HTML form表单值(POST方法),虽然在一些情况下也会有其他操作。
  • 要获取的资源的路径,通常是上下文中就很明显的元素资源的URL,它没有protocol (http://),domain(developer.mozilla.org),或是TCP的port (en-US)(HTTP一般在80端口)。
  • HTTP协议版本号。
  • 为服务端表达其他信息的可选头部headers。
  • 对于一些像POST这样的方法,报文的body就包含了发送的资源,这与响应报文的body类似。

一个完整的HTTP请求报文包含:请求行,请求头,空行和请求数据。

下图给出了请求报文的一般格式。


4.1.1 请求方法

HTTP 定义了一组请求方法, 以表明要对给定资源执行的操作。指示针对给定资源要执行的期望动作. 虽然他们也可以是名词, 但这些请求方法有时被称为HTTP动词. 每一个请求方法都实现了不同的语义, 但一些共同的特征由一组共享:: 例如一个请求方法可以是 安全, 幂等, 或 可缓存.

1.0定义了三种请求方法:GET,POST和HEAD方法

1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

方法名称功能
GETGET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.
HEADHEAD方法请求一个与GET请求的响应相同的响应,但没有响应体.
POSTPOST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用.
PUTPUT方法用请求有效载荷替换目标资源的所有当前表示。
DELETEDELETE方法删除指定的资源。
CONNECTCONNECT方法建立一个到由目标资源标识的服务器的隧道。
OPTIONSOPTIONS方法用于描述目标资源的通信选项。
TRACETRACE方法沿着到目标资源的路径执行一个消息环回测试。
PATCHPATCH方法用于对资源应用部分修改。

最常用的方法是get和post

  • get

其实简单来说,GET方法一般用来负责获取数据,或者将一些简短的数据放到URL参数中传递到服务器。比POST更加高效和方便。

  • POST

由于GET方法最多在url中携带1024字节数据,且将数据放到URL中传递太不安全,数据量大时URL也会变得冗长。所以传递数据量大或者安全性要求高的数据的时候,最好使用POST方法来传递数据。

4.1.2 请求头

HTTP 消息头允许客户端和服务器通过 request和 response传递附加信息。一个请求头由名称(不区分大小写)后跟一个冒号“:”,冒号后跟具体的值(不带换行符)组成。该值前面的引导空白会被忽略。

报头名 + : + 值

根据不同上下文,可将消息头分为:

  • General headers: 同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。
  • Request headers: 包含更多有关要获取的资源或客户端本身信息的消息头。
  • Response headers: 包含有关响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。
  • Entity headers: 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。

常见请求头及其作用:

名称作用
Host指定的请求资源的域名(主机和端口号)。HTTP请求必须包含HOST,否则系统会以400状态码返回。
User-Agant简称UA,内容包含发出请求的用户信息,通常UA包含浏览者的信息,主要是浏览器的名称版本和所用的操作系统。这个UA头不仅仅是使用浏览器才存在,只要使用了基于HTTP协议的客户端软件都会发送,无论是手机端还是PDA等,这个UA头是辨别客户端所用设备的重要依据。
Accept告诉服务器客户端可以接受那些类型的信息。
CookieCookie信息。
Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、man-age、max-stake、min-fresh、only-if-cached;响应消息中的指令包括 public、privete、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。
Referer页面跳转处,表明产生请求的网页来自于哪个URL,用户是从该 Referer页面访问到当前请求的页面。这个属性可以用来跟踪Web请求来自哪个页面,是从什么网站来的。
Content-Type来表示具体请求中的媒体类型信息,例如 text/html 代表 HTML 格式,image/gif 代表 GIF 图片,application/json 代表 Json 类型
Content-Length内容长度。
Content-Range响应的资源范围。可以在每次请求中标记请求的资源范围,在连接断开重连时,客户端只请求该资源未下载的部分,而不是重新请求整个资源,实现断点续传。迅雷就是基于这个原,使用多线程分段读取网络上的资源,最后再合并。
Accept-Encoding指定所能接收的编码方式,通常服务器会对页面进行GZIP压缩后再输出以减少流量,一般浏览器均支持对这种压缩后的数据进行处理,但对于我们来说,如果不想接收到这些看似乱码的数据,可以指定不接收任何服务器端压缩处理,要求其原样返回。
Accept-Language指浏览器可以接受的语言种类 en、en-us指英语 zh、zh-cn指中文。
Connection客户端与服务器链接类型,keep-alive:保持链接,close:关闭链接。

更多请求头和作用请看https://developer.mozilla.org/zh-CN/docs/Web/HTTP

4.1.3 请求数据

请求数据通常是使用POST方法进行发送的,GET方法是没有请求数据的。

请求数据跟上面的消息报头由一个空行隔开。

4.2. http响应(response)

HTTP响应的一个例子:

文包含了下面的元素:

  • HTTP协议版本号。
  • 一个状态码(status code),来告知对应请求执行成功或失败,以及失败的原因。
  • 一个状态信息,这个信息是非权威的状态码描述信息,可以由服务端自行设定。
  • HTTP headers,与请求头部类似。
  • 可选项,比起请求报文,响应报文中更常见地包含获取的资源body。

一个完整的HTTP响应报文也由四个部分组成,分别是:状态行,消息报头,空行和响应正文。

4.2.1 响应状态码

当客户端向服务端发起一次请求后,服务端在返回的响应头中会包含一个HTTP状态码。 HTTP的状态码是由三位数字来表示的,由第一位数字来表示状态码的类型,一般来说有五种类型:

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

4.2.2 响应报头

状态行下方的就是响应报头。常见响应报头如下:

报头功能描述
Allow服务器支持哪些请求方法(如GET、POST等)。
Date表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。
Set-Cookie非常重要的header, 用于把cookie发送到客户端浏览器,每一个写入cookie都会生成一个Set-Cookie。
Expires指定 Response 的过期时间 ,从而不再缓存它,重新从服务器获取,会更新缓存。过期之前使用本地缓存。降低服务器负载,缩短加载时间。
Content-TypeWEB服务器告诉客户端自己响应的对象的类型和字符集。
Content-Encoding文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。
Content-Length指明实体正文的长度,以字节方式存储的十进制数字来表示。
Location用于重定向一个新的位置,包含新的URL地址。表示客户应当到哪里去提取文档。
Refresh表示浏览器应该在多少时间之后刷新文档,以秒计。

更详细的响应报头请看 https://developer.mozilla.org/zh-CN/docs/Web/HTTP

4.2.3 响应数据

响应报文中空行后的内容就是响应数据了。

5. url

URL(Uniform Resource Locator),中文叫统一资源定位符。是用来标识某一处网络资源的地址。在 HTTP 的上下文中,URL 被叫做”网络地址“或“链接”。以下面这个URL为例,介绍下普通URL的各部分组成:

6.https

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版

http协议是基于tcp/ip协议的,而https是在http协议的基础之上,再加了一层SSL/TLS协议,数据在传输过程中是加密的。

  1. https协议需要到ca申请证书,一般免费证书很少,需要交费。

  2. http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。

  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

7. HTTP/1.x 的连接管理

连接管理是一个 HTTP 的关键话题:打开和保持连接在很大程度上影响着网站和 Web 应用程序的性能。在 HTTP/1.x 里有多种模型:短连接, 长连接, 和 HTTP 流水线。

HTTP 的传输协议主要依赖于 TCP 来提供从客户端到服务器端之间的连接。在早期,HTTP 使用一个简单的模型来处理这样的连接。这些连接的生命周期是短暂的:每发起一个请求时都会创建一个新的连接,并在收到应答时立即关闭。

这个简单的模型对性能有先天的限制:打开每一个 TCP 连接都是相当耗费资源的操作。客户端和服务器端之间需要交换好些个消息。当请求发起时,网络延迟和带宽都会对性能造成影响。现代浏览器往往要发起很多次请求(十几个或者更多)才能拿到所需的完整信息,证明了这个早期模型的效率低下。

有两个新的模型在 HTTP/1.1 诞生了。首先是长连接模型,它会保持连接去完成多次连续的请求,减少了不断重新打开连接的时间。然后是 HTTP 流水线模型,它还要更先进一些,多个连续的请求甚至都不用等待立即返回就可以被发送,这样就减少了耗费在网络延迟上的时间。

8.鉴权与授权

为什么有些页面能够直接访问,有些页面需要登陆后才能访问呢?

基于http协议的网络应用是如何进行权限管理的呢?

权限管理包含授权,和鉴权。

目前常见的权限管理有两种方式:会话技术和jwt授权。

8.1 会话技术

http是无状态的,那服务端怎么区分同一个用户的连续请求呢,这就用到了会话技术:cookie和session。

8.1.1 cookie技术

Cookie有时也用其复数形式 Cookies,英文是饼干的意思。指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

Cookie其实就是由服务器发给客户端的特殊信息,而这些信息存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。 服务器在接收到Cookie以后,会验证Cookie的信息,以此来辨别用户的身份。

Cookie可以理解为一个凭证。

cookie一般的保存格式为json格式,由一些属性组成。

  • name:Cookie的名称
  • value:Cookie的值
  • domain:可以使用此Cookie的域名
  • path:可以使用此Cookie的页面路径
  • expires/Max-Age:此Cookie的超时时间
  • secure:设置是否只能通过https来传递此条Cookie

8.1.2 session

Session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。这个词在各个领域都有在使用。

而我们web领域,一般使用的是其本义,一个浏览器窗口从打开到关闭这个期间。

Session的目的则是,在一个客户从打开浏览器到关闭浏览器这个期间内,对同一个网站发起的所有请求都可以被识别为同一个用户。

session认证的流程一般如下:

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
  3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

因此session是基于cookie的

Session与Cookie相反,Session是存储在服务器上的数据,只由客户端传上来的SessionId来进行判定,所以相对于Cookie,Session的安全性更高。

一般SessionID会在浏览器被关闭时丢弃,或者服务器会验证Session的活跃程度,例如30分钟某一个SessionID都没有活跃,那么也会被识别为失效。

实际场景
当我们登录之后,服务端就会创建一个属于当前用户的 Session,里面保存的就是当前用户的信息;
然后浏览器会根据服务器的响应头中 Set-Cookie 字段生成相关 Cookie,相当于一个用户凭证
只需要在下次请求时携带这些 Cookie,服务器就能通过 Cookie 来判断用户是否是登录状态,然后返回对应的响应
不好理解?继续往下看!

生动形象理解Cookie和Session的关系
Session 是保存在服务器端,Cookie 是保存在客户端
每次用户访问网站的时候,相当于去串门
用户带着 cookie 去服务器家,当当当敲门
服务器问是谁啊
用户:是我(cookie)啊
服务器:让我来确认一下(session确认)
服务器确认完毕后,放用户进门

实际网站登录请求的响应头
这是一个网站登录之后返回的响应头,可以看到服务器要求浏览器设置的 Cookies 有好几个;这就是 Cookies 的来源,而 token 一般会作为用户的唯一凭证【登录成功,响应头set-cookies,浏览器设置Cookies】
当浏览器下一次再请求该网站时,浏览器会把这些Cookies放到请求头一起提交到服务器;而Cookies携带了SessionID信息(x-token)【再次请求,带上 cookies,包含 SessionID】
服务器通过 SessionID 即可找到对应的用户 Session 信息,然后判断该用户的登录状态【服务器根据 SessionID 获取用户信息】
如果 Session 中某些设置登录状态的变量是有效期内的,证明用户处于登录状态【Session 有效,用户已登录】
此时服务器就会返回需要登录之后才可以查看的网页内容,浏览器再进行解析便可以看到了【返回请求响应内容】
当 Cookie 无效或者 Session 已过期后,我们再访问网站就需要重新登录了【Cookie 无效,Session 过期,需要再次登录】

8.2 JWT

8.2.1 JWT 原理

JSON Web Token (缩写JWT)是目前最流行的跨域认证解决方案。

jwt的原理是,服务器认证以后,生成一个JSON对象,发回给用户,就像下面这样。

{
  "姓名": "心蓝",
  "角色": "管理员",
  "到期时间": "2020年10月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

8.2.2 JWT的数据结构

实际的 JWT 大概就像下面这样。

 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJ1c2VybmFtZSI6InB5MzQiLCJleHAiOiIxNjAxNDU4ODI2LjM5MjU5NyJ9. e1c994e615cfbf3a81a13076b7d05c98a752bbd9381f551ad568ef287d439980

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

JWT 的三个部分依次如下。

  • Header(头部)
  • Payload(负载)
  • Signature(签名)
8.2.3 JWT的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

Authorization: Bearer <token>

另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

所以我们测试碰到JWT时要根据开发的使用方式进行对应的测试。

上一篇 下一篇