HTTP 协议

date
Jun 18, 2023
slug
HTTP 协议
status
Published
tags
IT
HTTP
summary
HTTP 协议
type
Post

前言

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

请求和响应

HTTP请求组成:请求行、消息报头、请求正文。 HTTP响应组成:状态行、消息报头、响应正文。
请求行组成:以一个方法符号开头,后面跟着请求的URI和协议的版本。 状态行组成:服务器HTTP协议的版本,服务器发回的响应状态代码和状态代码的文本描述。
请求报文如图
notion image
notion image
响应报文如图
notion image
第一行是状态行
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
  • 1xx:指示信息--表示请求已接收,继续处理
  • 2xx:成功--表示请求已被成功接收、理解、接受
  • 3xx:重定向--要完成请求必须进行更进一步的操作
  • 4xx:客户端错误--请求有语法错误或请求无法实现
  • 5xx:服务器端错误--服务器未能实现合法的请求
脑图
notion image

请求方法

常见的 HTTP 请求方法如下:
  • GET: 请求获取 Request-URI 所标识的资源(4K 大小)。
  • POST: 在 Request-URI 所标识的资源后附加新的数据(修改数据)。
  • HEAD: 请求获取由 Request-URI 所标识的资源的响应消息报头(简易版的 get,只返回请求头)。
  • PUT: 请求服务器存储一个资源,并用 Request-URI 作为其标识(增加数据)。
  • DELETE:请求服务器删除 Request-URI 所标识的资源。
  • TRACE: 请求服务器回送收到的请求信息,主要用于测试或诊断 。
  • CONNECT:保留将来使用 。
  • OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求。

请求报头

常见的 HTTP 请求报头如下:
  • Accept 请求报头域用于指定客户端接受哪些类型的信息。eg:Accept:image/gif,Accept:text/ html。
  • Accept-Charset 请求报头域用于指定客户端接受的字符集。
  • Accept-Encoding:Accept-Encoding 请求 报头域类似于 Accept,但是它是用于指定可接受的内容编码。
  • Accept-Language 请求报头域类似于 Accept,但是它是用于指定一种自然语言。
  • Authorization 请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收 到服务器的响应代码为 401(未授权),可以发送一个包含 Authorization 请求报头域的请求,要求服务 器对其进行验证。
  • Host 请求报头域主要用于指定被请求资源的 Internet 主机和端又号,它通常从 HTTP URL 中提取出来 的,发送请求时,该报头域是必需的。
  • User-Agent 请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器

响应报头

常见的 HTTP 响应报头如下:
  • Location 响应报头域用于重定向接受者到一个新的位置。Location 响应报头域常用在更换域名的时候。
  • Server 响应报头域包含了服务器用来处理请求的软件信息。与 User- Agent 请求报头域是相对应的。
  • WWW-Authenticate 响应报头域必须被包含在 401(未授权的)响应消息中,客户端收到 401 响应消息时候,并发送 Authorization 报头域请求服务器对其进行验证时,服务端响应报头就包含该报头域。

实体报头

每一个请求和响应消息都可以传送一个实体。一个实体由实体报头和实体正文组成,但并不是说实体报头和实体正文要在一起发送,可以只发送实体报头。在实体报头中定义了关于实体正文和请求所标识的资源的元信息。
  • Content-Encoding 实体报头被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得 Content-Type 报头域中所引用的媒体类型,必须采用相应的解 码机制。
  • Content-Language 实体报头描述了资源所用的自然语言。
  • Content-Length 实体报头用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
  • Content-Type 实体报头用语指明发送给接收者的实体正文的媒体类型。 Last-Modified 实体报头用于指示资源的最后修改日期和时间。 Expires 实体报头给出响应过期的日期和时间。

HTTP的发展

话不多说,上大图
notion image

HTTP/0.9

HTTP 最早版本是 1991 年发布的 0.9 版。该版本极其简单,只有一个命令 GET。
上面命令表示,TCP 连接建立后,客户端向服务器请求网页 index.html。
协议规定,服务器只能响应 HTML 格式的字符串,不能响应别的格式。
服务器发送完毕,就关闭 TCP 连接。

HTTP/1.0

1996 年 5 月,HTTP/1.0 版本发布,内容大大增加。
首先,任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。这为互联网的大发展奠定了基础。
其次,除了 GET 命令,还引入了 POST 命令和 HEAD 命令,丰富了浏览器与服务器的互动方式。
再次,HTTP 请求和响应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。
其他的新增功能还包括状态码、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。
下面是一个 1.0 版的 HTTP 请求的例子。
第一行是请求命令,必须在尾部添加协议版本(HTTP/1.0)。后面就是多行头信息,描述客户端的情况。

响应格式

服务器的响应如下。
响应的格式是头信息 + 空行 + 数据。其中,第一行是协议版本 + 状态码 + 状态描述

HTTP/1.0 缺点

HTTP/1.0 版的主要缺点是,每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。
TCP 连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(慢启动)。所以,HTTP/1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
为了解决这个问题,有些浏览器在请求时,用了一个非标准的 Connection: keep-alive 字段。
这个字段要求服务器不要关闭 TCP 连接,以便其他请求复用。服务器同样响应这个字段Connection: keep-alive
一个可以复用的 TCP 连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。

HTTP/1.1

1997 年 1 月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了 20 年后的今天,直到现在还是最流行的版本。

持久连接

HTTP/1.1 版的最大变化,就是引入了持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close,明确要求服务器关闭 TCP 连接。
目前,对于同一个域名,大多数浏览器允许同时建立 6 个持久连接。

管道机制

HTTP/1.1 版还引入了管道机制(pipelining),即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率。
举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出响应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照顺序,先响应 A 请求,完成后再响应 B 请求。

Content-Length 字段

一个 TCP 连接现在可以传送多个响应,势必就要有一种机制,区分数据包是属于哪一个响应的。这就是 Content-length 字段的作用,声明本次响应的数据长度。
上面代码告诉浏览器,本次响应的长度是 3495 个字节,后面的字节就属于下一个响应了。
在 1.0 版中,Content-Length 字段不是必需的,因为浏览器发现服务器关闭了 TCP 连接,就表明收到的数据包已经全了。

分块传输编码

分块传输编码是指将数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。
使用 Content-Length 字段的前提条件是,服务器发送响应之前,必须知道响应的数据长度。
对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。
因此,HTTP/1.1 版规定可以不使用 Content-Length 字段,而使用分块传输编码。只要请求或响应的头信息有 Transfer-Encoding 字段,就表明响应将由数量未定的数据块组成。
每个非空的数据块之前,会有一个 16 进制的数值,表示这个块的长度。最后是一个大小为 0 的块,就表示本次响应的数据发送完了。下面是一个例子。

其他功能

HTTP/1.1 版还新增了许多请求方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。
另外,客户端请求的头信息新增了 Host 字段,用来指定服务器的域名。
有了 Host 字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

HTTP/1.1 缺点

虽然 1.1 版允许复用 TCP 连接,但是同一个 TCP 连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个响应,才会进行下一个响应。要是前面的响应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。
为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入 CSS 代码、域名分片(domain sharding)等等。如果 HTTP 协议设计得更好一些,这些额外的工作是可以避免的。

HTTP/2

2015 年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。

二进制协议

HTTP/1.1 版的头信息只能是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧和数据帧。
二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。
HTTP2 二进制分帧图:
notion image

多路复用

HTTP/2 复用 TCP 连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或响应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。
举例来说,在一个 TCP 连接里面,服务器同时收到了 A 请求和 B 请求,于是先响应 A 请求,结果发现处理过程非常耗时,于是就发送 A 请求已经处理好的部分, 接着响应 B 请求,完成后,再发送 A 请求剩下的部分。
这样双向的、实时的通信,就叫做多路复用(Multiplexing)。

多路复用的发展史

notion image
  • 如图,使用 HTTP/2 的多路复用技术。将多个请求复用同一个 TCP 链接中,将一个 TCP 连接分为若干个流(Stream),每个流中可以传输若干消息(Message),每个消息由若干最小的二进制帧(Frame)组成。也就是将每个请求响应拆分为了细小的二进制帧(Frame),这样即使一个请求被阻塞了,也不会影响其他请求。

数据流

因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的响应。因此,必须要对数据包做标记,指出它属于哪个响应。
HTTP/2 将每个请求或响应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流 id,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流 id 一律为奇数,服务器发出的 id 为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM 帧),取消这个数据流。HTTP/1.1 版取消数据流的唯一方法,就是关闭 TCP 连接。这就是说,HTTP/2 可以取消某一次请求,同时保证 TCP 连接还打开着,可以被其他请求使用。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早响应。
数据流、消息、帧
  • 数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。(一次 http 请求)
  • 消息:与逻辑请求或响应消息对应的完整的一系列帧。(一个请求或响应)
  • 帧:HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流。(http 标头,消息负载等)
这些概念的关系总结如下:
  • 所有通信都在一个 TCP 连接上完成,此连接可以承载任意数量的双向数据流。
  • 每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息。
  • 每条消息都是一条逻辑 HTTP 消息(请求或响应),包含一个或多个帧。
  • 帧是最小的通信单位,承载着特定类型的数据,例如 HTTP 标头、消息负载等。 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
理解了这张图,数据流、消息、帧 就基本上懂了。
notion image

头信息压缩

HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
notion image

服务器推送

HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析 HTML 源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
服务器端推送:
notion image
在 HTTP2 中,服务端可以在客户端某个请求后,主动推送其他资源。
可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用 prefetch 。

HTTP/2 缺点

虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题:因为 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。当这个连接中出现了丢包的情况,整个 TCP 都要开始等待重传,也就导致了所有数据都被阻塞了。
虽然这个问题并不是它本身造成的,而是底层支撑的 TCP 协议的问题。那么可能就会有人考虑到去修改 TCP 协议,其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。

HTTP/3

待续

Cookie 与 Session

  • Cookies 是保存在客户端的小段文本,随客户端点每一个请求发送该url 下的所有 cookies 到服务器端。 • Session 则保存在服务器端,通过唯一的值 sessionID 来区别每一个用 户。SessionID 随每个连接请求发送到服务器,服务器根据 sessionID 来识 别客户端,再通过 session 的 key 获取 session 值。

Cookie 使用

  • 与 Cookie 相关的 HTTP扩展头 1) Cookie:客户端将服务器设置的 Cookie 返回到服务器; 2)Set-Cookie:服务器向客户端设置 Cookie ; • 服务器在响应消息中用 Set-Cookie 头将 Cookie 的内容回送给客户端,客户端在 新的请求中将相同的内容携带在 Cookie 头中发送给服务器。从而实现会话的保 持。
notion image

Session 的使用

  • 使用 Cookie 来实现 • 使用 URL 回显来实现
notion image

参考文章

一文读懂 HTTP/2 及 HTTP/3 特性https://blog.fundebug.com/2019/03/07/understand-http2-and-http3/

© xiaosen chen 2022 - 2024 ❤ LOVE