6.4.3 HTTP(P276 6.4.3)
HTTP 协议是现代互联网中广泛使用的协议。
HTTP 协议本身是无状态协议,但基于 HTTP 协议的应用可以通过适当的机制(如会话管理和状态保持)实现有状态的行为。
HTTP 协议通常监听 80 端口;HTTPS 是在 HTTP 上增加了 TLS/SSL 加密层,通常监听 443 端口。
HTTP 协议截止本文编写时(2024 年)拥有 HTTP/1.0(RFC-1945)、HTTP/1.1(RFC-7231)、HTTP/2(RFC-7540)、HTTP/3(RFC-9000)共 4 个版本。
(P276 6.4.3 图 6-8)HTTP 会话分为 4 个阶段:
- 建立 TCP 连接
- 客户端发送 HTTP 请求报文
- 服务端发送 HTTP 响应报文
- 释放 TCP 连接
相关词条:
-
无状态(Stateless)
每次请求都是独立的,服务器不记录之前的请求状态或信息。这样做简化了逻辑,减少了资源消耗。
-
有状态(Stateful)
服务器会记住或维护客户端的状态信息,以便在随后的交互中使用。适合需要保持用户上下文的应用,如在线购物、社交媒体、登录系统等。
6.4.3.1 HTTP/1.1
HTTP/1.1 基于 TCP 协议。一个完整的 HTTP 报文通常包含以下几种元素:
-
HTTP 方法(RFC-1945 8)
方法出现在 HTTP 请求报文中。常见请求方法如下:
-
GET:用于获取指定资源。
-
HEAD:作用与 GET 方法相同,但响应中仅包含 HTTP 响应头,不包含任何响应体。
-
POST:用于提交数据,通常用于创建新资源。
-
PUT:用于更新指定资源,若指定资源不存在则创建新的资源。
-
DELETE:用于删除指定资源。
-
CONNECT:用于与服务器 建立一个隧道连接,通常用于 HTTPS 或 WebSocket。
当对方请求使用的方法不被支持时,应返回状态码 405。
-
-
HTTP URL
出现在 HTTP 请求报文中,表明所请求资源的唯一标识符。
-
HTTP 状态码(RFC-1945 9)
状态码出现在 HTTP 响应报文中,通常表示为“状态码 状态描述”,例如“200 OK”,常见见状态码包含下列几组:
-
2xx(成功):
- 200 OK:表明请求成功。
- 204 No Content:表明请求已处理,但没有新的内容可响应。
-
3xx(重定向):
- 301 Moved Permanently:表明请求的资源已被永久分配了一个新的 URL,浏览器通常会永久缓存此请求结果。
- 302 Found:表明请求的资源被临时分配了一个新的 URL,由于历史原因,用户可能会对新的 URL 使用 GET 请求。
- 304 Not Modified:通常用于响应附带了 If-Modified-Since 字段 GET 请求,详见后文。
- 307 Temporary Redirect:表明请求的资源被临时分配了一个新的 URL,用户请求新的 URL 时不得更改请求方法。
-
4xx(客户端错误):
通常用于表明客户端发送了错误的请求,应检查请求是否正确。
- 400 Bad Request:表明 HTTP 请求报文语法错误,服务端无法处理。
- 401 Unauthorized:表明该请求需要用户身份验证。
- 403 Forbidden:表明服务器理解该请求,但拒绝响应,且此错误并非由身份验证导致。
- 404 Not Found:表明服务器并未找到任何与请求的 URI 匹配的内容。
- 405 Method Not Allowed:表明服务器已知客户端所使用的请求方法,但目标资源不支持此方法。
- 408 Request Timeout:表明服务器等待客户端发送完整请求时超时。
- 413 Payload Too Large:表明请求体过大,服务器拒绝处理请求。
-
5xx(服务端错误):
通常用于表明服务器意识到自身已出现错误或无法执行请求。
- 500 Internal Server Error:表明服务器遇到了内部错误,无法完成请求。
- 501 Not Implemented:表明服务器并未实现所请求的功能。
- 502 Bad Gateway:表明服务器在充当网管或代理,但无法从上游服务中收到有效的响应。
- 503 Service Unavailable:表明服务器暂不可用。
- 504 Gateway Timeout:表明服务器在充当网管或代理,但从上游服务中获取响应时超时。
- 505 HTTP Version Not Supported:表明服务器拒绝处理请求所使用的 HTTP 版本。
-
-
HTTP 标头(RFC-1945 10) 标头同时出现在请求报文和响应报文中,通常分别称为请求头和响应头。常见的标头如下:
-
Allow:通常出现在响应头中,用于表明请求的 URI 允许的请求方法,若响应状态码为 405 则必须包含此字段。例如:
Allow: GET, HEAD
-
Accept-Charset/Accept-Encoding/Accept-Language:通常出现在请求头中,用于表明所期望响应的字符编码、内容编码、自然语言。例如:
Accept-Charset: UTF-8
Accept-Encoding: gzip
Accept-Language: zh-Hans -
Connection:HTTP/1.1 支持将多个 HTTP 请求放入同一个 TCP 连接中,此字段用于向服务器表明 HTTP 请求完成后的处理方式。例如请求后不要关闭连接:
Connection: Keep-Alive
-
Content-Language:用于表明 HTTP 报文主体所使用的自然语言。例如:
Content-Language: zh-Hans
-
Authorization:通常出现在请求头中,用于向服务器验证身份。例如使用 Basic 方式认证:
Authorization: Basic zsWxgaSGsSgaxG...
-
Content-Encoding:用于表明 HTTP 报文主体的编码类型。例如:
Content-Encoding: x-gzip
-
Content-Length:用于表明 HTTP 报文主体的长度,以字节为单位,表示为十进制数。例如:
Content-Length: 114514
-
Content-Type:用于表明 HTTP 报文主体的数据类型,与 MIME 所定义的相同。例如:
Content-Type: text/html
-
Host:通常出现在请求头中,HTTP/1.1 要求请求头中必须包含此字段,用于表明发起请求时所使用的主机名称。例如:
Host: www.w3.org
-
If-Modified-Since:通常出现在 GET 请求的请求头中,用于向服务器告知若指定的资源在指定 的时间后有修改才返回内容,否则将返回 304。其中时间的格式遵循 RFC-822。例如:
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
-
Last-Modified:通常出现在响应头中,用于向客户端展示请求的资源上一次修改的时间。其中时间的格式遵循 RFC-822。例如:
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
-
Location:通常出现在状态码为 301 或 302 的响应头中,用于表明该资源新的 URL。例如:
Location: http://www.w3.org/hypertext/WWW/NewLocation.html
-
Referer:通常出现在请求头中,当一个用户在浏览器中点击链接时,浏览器会在发出的请求中添加 Referer 头,包含原始页面的地址。例如:
Referer: http://www.w3.org/hypertext/DataSources/Overview.html
-
Server:通常出现在响应头中,用于标识服务器的软件信息。例如:
Server: nginx/1.20.1
-
User-Agent:通常出现在请求头中,用于标识发起请求的用户代理的信息。例如当用户使用 Edge 浏览器发起请求,则 User-Agent 通常为:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0
-
WWW-Authenticate:通常出现在状态码为 401 的响应头中,用于向客户端表明身份验证所需要的方法。例如:
WWW-Authenticate: Basic realm="WallyWorld"
-
-
HTTP 主体
可出现在 HTTP 请求报文和 HTTP 响应报文中,通常分别称为请求体和响应体。
RFC 文档中没有限定 GET 请求是否可以包含请求体,但实践中通常不携带请求体。
一个 HTTP 请求报文示例如下:
GET /hello.html HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0
Host: www.w3.org
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
此报文表示使用 URL:http://www.w3.org/hello.html,发起 GET 请求。
响应报文示例如下:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Keep-Alive
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
6.4.3.2 HTTP/1.1 与其他版本的主要区别
HTTP/1.0 vs HTTP/1.1:
- 持久连接:HTTP/1.1 默认支持持久连接,即允许将多个请求在同一个 TCP 连接中进行。HTTP/1.0 每个请求都需要建立新的连接。
- Host 请求头:HTTP/1.1 要求请求头中必须包含 Host 字段,以支持虚拟主机。
- 流水线(Pipelining):HTTP/1.1 支持流水线请求,即连续依次发送多个 GET 请求,而不必等待服务器响应后再发送下一个 GET 请求。
HTTP/1.1 vs HTTP/2:
- 二进制格式:HTTP/2 定义了一个新的二进制帧,要求所有请求和响应都分解为二进制帧,提高了传输效率。
- 多路复用:HTTP/2 允许在同一连接上并发的执行多个请求,而不会相互阻塞。
- 头部压缩:HTTP/2 使用 HPACK 算法压缩头部。即创建头部字段的引用,以在后续请求中直接使用而非重复传输整个字段,HPACK 拥有一个静态表,预定义了常见头部字段,此外还拥有一个动态表,可以在传输过程中新增定义头部字段。
- 服务器推送:HTTP/2 支持服务器向客户端主动推送二进制帧,例如当客户端请求一个 HTML 页面时,服务器可以同时向客户端推送 CSS 和 JavaScript 文件,而非等待客户端解析 HTML 后自行请求,这样减少了请求数量。
HTTP/2 vs HTTP/3:
- 使用 QUIC:HTTP/3 换用了基于 UDP 协议的 QUIC 协议,减少了连接建立延迟、提高了多方面的性能。
- 强制加密:HTTP/2 支持使用加密,但并非强制,HTTP/3 强制使用 TLS 1.3 加密。