HTTP协议(二):深入理解请求和响应报文的构成

在上一篇博客中,我们介绍了 HTTP 协议的基本概念和工作原理。如果说 HTTP 协议是 Web 通信的“通用语言”,那么 HTTP 报文就是承载具体“对话内容”的载体。无论是你通过浏览器访问一个网页,还是手机 App 从服务器获取数据,背后都是 HTTP 报文在辛勤地工作。

本文将深入剖析 HTTP 报文的结构,分别详细讲解请求报文响应报文的各个组成部分。理解这些构成要素,是进行 Web 开发、API 设计、性能优化和故障排查的基础。我们将通过具体的实例和最佳实践,帮助你彻底掌握这一核心知识。

目录#

  1. HTTP 报文概述
  2. HTTP 请求报文详解
  3. HTTP 响应报文详解
  4. 常见实践与最佳实践
  5. 实例分析
  6. 总结
  7. 参考资料

一、 HTTP 报文概述#

HTTP 报文是在 HTTP 应用程序之间发送的数据块。这些数据块以一些文本形式的元信息(meta-information)开头,这些元信息描述了报文的内容和含义,后面跟着可选的数据部分。

HTTP 报文分为两类:

  • 请求报文: 从客户端发往服务器的报文。
  • 响应报文: 从服务器发往客户端的报文。

HTTP 报文由三部分组成(对请求和响应来说,第三部分是可选的):

  1. 起始行: 描述请求或响应的基本信息。
  2. 首部字段: 包含各种属性,以键值对的形式描述报文。
  3. 空行: 用来分隔首部和主体。
  4. 报文主体: 实际传输的数据,如 HTML 内容、图片、JSON 数据等。

通用报文结构:

[起始行]
[首部字段名1]: [值1]
[首部字段名2]: [值2]
...
[空行]
[报文主体]

二、 HTTP 请求报文详解#

请求报文是客户端向服务器“要东西”或“提交东西”时发出的报文。

2.1 请求行#

请求报文的第一行是请求行,它说明了“要做什么”,包含三个部分:

  • 请求方法: 表示操作类型,如 GET(获取资源)、POST(提交数据)。
  • 请求目标: 通常是 URL 的路径和查询字符串部分,表示资源的位置。
  • HTTP 版本: 如 HTTP/1.1HTTP/2

格式: [方法] [请求目标] [HTTP版本]

示例: GET /api/users?id=123 HTTP/1.1

2.2 请求头#

请求行之后是请求头。每个首部字段都是一行,格式为 字段名: 值。它们提供了关于请求的附加信息,就像是给服务器的“备注”。

常见请求头:

  • Host必须的(在 HTTP/1.1 中),指定服务器的主机名和端口号。
  • User-Agent: 描述发起请求的客户端软件(浏览器、App等)。
  • Accept: 告知服务器客户端能够处理的内容类型,如 text/html, application/json
  • Content-Type当有请求体时重要,声明请求体的媒体类型,如 application/json
  • Content-Length: 声明请求体的长度(字节)。
  • Authorization: 包含用于验证客户端身份的凭证,如 Bearer Token。
  • Cookie: 将之前服务器设置的 Cookie 送回给服务器。

2.3 空行#

一个简单的回车换行符(\r\n),标志着请求头的结束。这是必须的,它告诉服务器:“我的头部信息已经发完了,后面如果有内容,就是请求体了。”

2.4 请求体#

请求体是可选的,通常用于 POSTPUT 等方法,用来携带需要发送给服务器的数据。例如,提交表单数据、上传文件或发送 JSON API 请求。

示例:

{
  "username": "john_doe",
  "email": "[email protected]"
}

三、 HTTP 响应报文详解#

响应报文是服务器处理完请求后,返回给客户端的报文。

3.1 状态行#

响应报文的第一行是状态行,它说明了“请求的结果如何”,包含三个部分:

  • HTTP 版本: 如 HTTP/1.1
  • 状态码: 一个三位数字,表示请求的成功或失败状态。
  • 原因短语: 对状态码的简短文字描述。

格式: [HTTP版本] [状态码] [原因短语]

示例: HTTP/1.1 200 OK

3.2 响应头#

与请求头类似,响应头提供了关于响应的附加信息。

常见响应头:

  • Server: 描述服务器的软件信息。
  • Content-Type非常重要的头,声明响应体的媒体类型,如 text/html; charset=UTF-8
  • Content-Length: 声明响应体的长度。
  • Set-Cookie: 服务器要求客户端设置一个 Cookie。
  • Cache-Control: 指示客户端如何缓存响应内容。
  • Location: 在重定向(状态码 3xx)时,指定重定向的目标 URL。

3.3 空行#

同样是一个回车换行符(\r\n),用来分隔响应头和响应体。

3.4 响应体#

响应体是服务器返回的实际内容,例如请求的 HTML 文档、图片数据、JSON 数据等。浏览器会解析这些内容并呈现给用户。


四、 常见实践与最佳实践#

4.1 请求方法的使用场景#

  • GET: 用于获取资源,不应有副作用(不修改服务器数据)。参数通过 URL 查询字符串传递。应幂等且安全
  • POST: 用于创建新资源或执行有副作用的操作(如付款)。数据通常放在请求体中。非幂等
  • PUT: 用于完整地更新一个已存在的资源。应幂等
  • PATCH: 用于对资源进行部分更新。
  • DELETE: 用于删除资源。应幂等

最佳实践: 遵循 RESTful API 设计原则,为不同的操作使用正确的 HTTP 方法。

4.2 重要首部字段详解#

  • Content-Type 与 Accept

    • Content-Type发送方声明“我发给你的是什么格式的数据”。
    • Accept接收方声明“我能处理哪些格式的数据,请按优先级返回”。
    • 最佳实践: API 接口应始终正确设置 Content-Type(如 application/json),并检查 Accept 头以支持内容协商。
  • 缓存控制

    • Cache-Control: max-age=3600 告诉浏览器可以缓存这个响应 3600 秒。
    • Cache-Control: no-cache 不意味着“不缓存”,而是“使用缓存前必须向服务器验证”。
    • 最佳实践: 对静态资源(图片、CSS、JS)设置较长的缓存时间,并通过在文件名中嵌入哈希值来实现缓存失效。
  • 授权

    • Authorization: Bearer <token> 是使用 JWT(JSON Web Token)进行 API 认证的常见方式。
    • 安全实践: 始终使用 HTTPS 来传输认证信息,防止凭证泄露。

4.3 状态码的正确使用#

  • 2xx 成功

    • 200 OK: 通用成功状态。
    • 201 Created: 资源创建成功,应在 Location 头中提供新资源的 URI。
    • 204 No Content: 请求成功,但响应体无内容(如 DELETE 成功)。
  • 3xx 重定向

    • 301 Moved Permanently: 永久重定向。
    • 302 Found: 临时重定向。
    • 304 Not Modified: 资源未修改,客户端可使用缓存。
  • 4xx 客户端错误

    • 400 Bad Request: 通用客户端错误,服务器无法理解请求。
    • 401 Unauthorized: 需要认证。
    • 403 Forbidden: 服务器理解请求,但拒绝执行(权限不足)。
    • 404 Not Found: 资源不存在。
  • 5xx 服务器错误

    • 500 Internal Server Error: 通用服务器错误。
    • 502 Bad Gateway: 网关或代理服务器从上游服务器收到无效响应。
    • 503 Service Unavailable: 服务器暂时过载或维护。

最佳实践: 为 API 接口选择最精确、最具描述性的状态码,帮助客户端正确处理响应。


五、 实例分析#

5.1 一个完整的 GET 请求示例#

场景: 浏览器请求用户列表页面。

请求报文:

GET /users?page=1 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: sessionId=abc123xyz

(此 GET 请求无请求体)

响应报文:

HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Mon, 23 Oct 2023 05:30:00 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 125
Cache-Control: max-age=60
 
{
  "users": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ],
  "totalPages": 5
}

5.2 一个完整的 POST 请求示例#

场景: 提交登录表单。

请求报文:

POST /login HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
Content-Type: application/json
Content-Length: 52
 
{"username": "john_doe", "password": "secret123"}

响应报文(成功):

HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: sessionToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; HttpOnly
Content-Length: 45
 
{"status": "success", "message": "Logged in"}

响应报文(失败,密码错误):

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 40
 
{"status": "error", "message": "Invalid credentials"}

六、 总结#

HTTP 请求和响应报文是 Web 通信的基石。通过本文的分解,我们了解到:

  1. 请求报文请求行、请求头、空行、请求体构成,核心是表达“要什么”和“怎么要”。
  2. 响应报文状态行、响应头、空行、响应体构成,核心是告知“结果如何”和“内容是什么”。
  3. 首部字段在控制缓存、内容协商、认证、Cookies 等方面扮演着至关重要的角色。
  4. 正确使用 HTTP 方法状态码 是设计清晰、符合规范的 Web 应用和 API 的关键。

深入理解这些构成,将使你能够更好地进行 Web 开发、调试网络问题、优化应用性能并设计出健壮的 API。


七、 参考资料#

  1. RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
  2. RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
  3. MDN Web Docs - HTTP: https://developer.mozilla.org/zh-CN/docs/Web/HTTP
  4. 《HTTP权威指南》 by David Gourley, Brian Totty