HTTP协议(二):深入理解请求和响应报文的构成
在上一篇博客中,我们介绍了 HTTP 协议的基本概念和工作原理。如果说 HTTP 协议是 Web 通信的“通用语言”,那么 HTTP 报文就是承载具体“对话内容”的载体。无论是你通过浏览器访问一个网页,还是手机 App 从服务器获取数据,背后都是 HTTP 报文在辛勤地工作。
本文将深入剖析 HTTP 报文的结构,分别详细讲解请求报文和响应报文的各个组成部分。理解这些构成要素,是进行 Web 开发、API 设计、性能优化和故障排查的基础。我们将通过具体的实例和最佳实践,帮助你彻底掌握这一核心知识。
目录#
一、 HTTP 报文概述#
HTTP 报文是在 HTTP 应用程序之间发送的数据块。这些数据块以一些文本形式的元信息(meta-information)开头,这些元信息描述了报文的内容和含义,后面跟着可选的数据部分。
HTTP 报文分为两类:
- 请求报文: 从客户端发往服务器的报文。
- 响应报文: 从服务器发往客户端的报文。
HTTP 报文由三部分组成(对请求和响应来说,第三部分是可选的):
- 起始行: 描述请求或响应的基本信息。
- 首部字段: 包含各种属性,以键值对的形式描述报文。
- 空行: 用来分隔首部和主体。
- 报文主体: 实际传输的数据,如 HTML 内容、图片、JSON 数据等。
通用报文结构:
[起始行]
[首部字段名1]: [值1]
[首部字段名2]: [值2]
...
[空行]
[报文主体]
二、 HTTP 请求报文详解#
请求报文是客户端向服务器“要东西”或“提交东西”时发出的报文。
2.1 请求行#
请求报文的第一行是请求行,它说明了“要做什么”,包含三个部分:
- 请求方法: 表示操作类型,如
GET(获取资源)、POST(提交数据)。 - 请求目标: 通常是 URL 的路径和查询字符串部分,表示资源的位置。
- HTTP 版本: 如
HTTP/1.1或HTTP/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 请求体#
请求体是可选的,通常用于 POST、PUT 等方法,用来携带需要发送给服务器的数据。例如,提交表单数据、上传文件或发送 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 通信的基石。通过本文的分解,我们了解到:
- 请求报文由请求行、请求头、空行、请求体构成,核心是表达“要什么”和“怎么要”。
- 响应报文由状态行、响应头、空行、响应体构成,核心是告知“结果如何”和“内容是什么”。
- 首部字段在控制缓存、内容协商、认证、Cookies 等方面扮演着至关重要的角色。
- 正确使用 HTTP 方法 和 状态码 是设计清晰、符合规范的 Web 应用和 API 的关键。
深入理解这些构成,将使你能够更好地进行 Web 开发、调试网络问题、优化应用性能并设计出健壮的 API。
七、 参考资料#
- RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
- RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
- MDN Web Docs - HTTP: https://developer.mozilla.org/zh-CN/docs/Web/HTTP
- 《HTTP权威指南》 by David Gourley, Brian Totty