Skip to content

HTTP 消息

基于客户端-服务器架构的 HTTP 通信依赖于消息交换。这些消息要么是客户端发送给服务器的请求(requests),要么是服务器发送回客户端的响应(responses)。这种请求/响应协议通常通过可靠的 TCP/IP 连接(或 HTTP/3 的 QUIC)运行。

HTTP 客户端(例如,Web 浏览器、移动应用程序或 curl 等工具)建立与服务器的连接,以发送一个或多个 HTTP 请求消息。HTTP 服务器(例如 Nginx、Apache、带有 Express 的 Node.js)接受这些连接,处理请求,并发送回 HTTP 响应消息。

HTTP 使用统一资源标识符(URIs),最常见的是 URL,来标识资源和建立连接。一旦建立连接(包括 HTTPS 的 TLS 握手),HTTP 消息就开始交换。对于 HTTP/1.1,这些消息是基于文本的,其头部格式结构类似于互联网邮件 (RFC 5322) 和 MIME (RFC 2045-2049)。HTTP/2 和 HTTP/3 使用二进制帧层进行消息传输,但保留了相同的语义组件。

HTTP/1.1 消息结构:
  • 一个起始行(Start-line):描述请求(对于请求)或其状态(对于响应)。
  • 零个或多个头部字段(Header fields):提供关于消息、资源或客户端/服务器的元数据。每个头部都是一个名值对(name-value pair),后跟 CRLF(回车换行)。
  • 一个空行(Empty line):一个单独的 CRLF,表示头部字段的结束。
  • 可选地,一个消息体(Message-body):包含有效负载数据(例如,HTML 内容、JSON 数据、图片字节)。
起始行类型:
`start-line = Request-Line | Status-Line`

我们将在 HTTP 请求和 HTTP 响应章节详细讨论 Request-Line 和 Status-Line。以下是一些示例:

// Request-Line sent by the client:
GET /index.html HTTP/1.1
// Status-Line sent by the server:
HTTP/1.1 200 OK

HTTP 头部字段提供关于请求或响应、或消息体中发送的对象的关键信息。头部在 HTTP/1.1 中是纯文本的,以冒号分隔名值对,名称不区分大小写。

头部类别(概念上的划分):

  • 通用头部(General Headers): 应用于请求和响应消息,但不应用于实体本身(例如 Connection, Date)。在较新的 RFC 中,这些大多被视为表现数据(Representation Data)或消息元数据(Message Metadata)。
  • 请求头部(Request Headers): 提供关于请求或客户端的更多信息(例如 User-Agent, Accept, Authorization)。
  • 响应头部(Response Headers): 提供关于响应或服务器的更多信息(例如 Server, Set-Cookie, Allow)。
  • 表现头部(Representation Headers)(以前称为实体头部 Entity Headers): 描述消息体的有效负载(例如 Content-Type, Content-Length, Content-Encoding)。如果不存在消息体,它们描述请求标识的资源。
所有头部都遵循通用格式:`header-field-name: field-value`

各种头部字段的示例:

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Host: www.example.com
Accept-Language: en-US,en;q=0.9
Date: Mon, 21 Feb 2022 12:28:53 GMT
Server: nginx/1.21.6
Last-Modified: Wed, 16 Feb 2022 19:15:56 GMT
ETag: "abcdef1234567890"
Content-Length: 1234
Content-Type: application/json; charset=utf-8
Connection: keep-alive

消息体(Message Body)是 HTTP 消息的可选部分。如果存在,它携带与请求或响应关联的有效负载。消息体的存在和解释通常由请求方法(例如,GET 和 HEAD 请求通常没有消息体)或响应状态码(例如,204 No Content 响应没有消息体)决定。

Content-Type 和 Content-Length 等头部描述消息体的性质和大小。消息体可以包含各种类型的数据:

  • Web 页面的 HTML、CSS、JavaScript。
  • API 通信的 JSON 或 XML。
  • 图片数据(JPEG、PNG、GIF、WebP)。
  • 纯文本。
  • 表单数据(application/x-www-form-urlencoded 或 multipart/form-data)。

JSON 消息体示例:

{
"username": "john.doe",
"email": "john.doe@example.com"
}

HTML 消息体示例:

<!DOCTYPE html>
<html>
<head><title>Hello</title></head>
<body>
<h1>Hello, World!</h1>
</body>
</html>

虽然概念结构(起始行、头部、消息体)保持不变,但 HTTP/2 和 HTTP/3 使用二进制帧。头部会被压缩(HPACK/QPACK),消息被分解成帧,这些帧可以在一个连接上交错传输。这显著提高了性能,但它是一个位于此处描述的 HTTP 语义之下的抽象层。