HTTP 报文是用于 HTTP 协议交互的信息。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务端)的则叫做响应报文。HTTP 报文本身是由多行(用空行:CR + LF 作为换行符)数据构成的字符串文本。
HTTP 报文大致可分为报文首部和报文主体两块,两者之间由空行(CR + LF)分割开。但 HTTP 报文也可以没有主体,只有报文首部信息。
HTTP 报文的结构
HTTP 的报文主要由报文首部、空行(CR + LF)和报文主体 3 部分组成:
- 报文首部:包含服务端或者客户端需要处理的请求或相应的内容及属性;
- 空行(CR + LF):CR(Carriage Return 回车符:16进制的 0x0d),LF(Lind Feed 换行符:16进制的 0x0a);
- 报文主体:发送 HTTP 请求的要发送的数据;
消息的起始行和 HTTP 标头统称为请求头,而其有效负载称为正文(报文主体)。其中,报文主体并不是每个 HTTP 报文都包含的。
请求报文的结构
请求报文首部的内容组成:
- 请求行:包含请求方法、请求 URI 和 HTTP 版本;
- 首部字段:包含表示请求的各个条件和属性的各类首部;
- 其它:可能包含 HTTP 的 RFC 里 未定义的首部(如 Cookie);
# 请求行 GET /blog/understanding-uri-and-url/ HTTP/1.1 # 首部字段 Host: www.yaohaixiao.com Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: wordpress_test_cookie=WP+Cookie+check; # 空行(CR + LF) # 其它 Cookie: Hm_lvt_cebfb56d60d4947826afe73a03c2=1623122954;
请求首部字段的类型
请求首部字段主要有 3 类类型:通用首部、请求首部、实体首部。
- 通用首部:过时的术语,当前版本的 HTTP/1.1 规范并未将标头明确归类为“通用标头”。用于指可在请求和响应消息中使用的 HTTP 首部,但不适用于内容本身(应用于内容的标头称为实体首部)。根据它们使用的上下文,通用标头可能是响应标头或请求标头;
- 请求首部:提供关于该请求的上下文信息,以便服务器可以定制响应。并非所有可以出现在请求中的标头都被规范称为请求标头。例如,Content-Type 标题被称为表示首部。;
- 表示首部:是一个 HTTP 标题描述的特定的表示,可能从请求返回的特定资源的不同版本。例如,相同的数据资源可能被格式化为 XML 或 JSON,然后该资源可能被编码为一种或多种压缩格式以供发送。客户端在内容协商期间指定他们喜欢的格式(使用Accept-*标头),表示首部告诉客户端他们实际收到的表示格式;
响应首部的结构
响应报文首部的内容组成:
- 状态行:包含表明相应结果的 HTTP 版本、状态码和原因短语;
- 首部字段:包含表示请求的各个条件和属性的各类首部;
- 其它:可能包含 HTTP 的 RFC 里 未定义的首部(如 Cookie);
# 状态行 HTTP/1.1 200 OK # 首部字段 Vary: Accept-Encoding Content-Type: text/html; charset=UTF-8 Content-Encoding: gzip Content-Length: 14759 Connection: keep-alive ETag: "66b79cb54cd71:0" Set-Cookie: sdwaf-test-item=5ce65d03520c0c53055d0501; path=/; HttpOnly # 空行(CR + LF) # 报文主体 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset='UTF-8'> <title>HTTP 报文</title> </head> <body> </body> </html>
响应首部字段的类型
响应首部字段主要有 3 类类型:通用首部、响应首部、实体首部。
- 通用首部:(过时的术语,当前版本的 HTTP/1.1 规范并未将标头明确归类为“通用标头”)用于指可在请求和响应消息中使用的 HTTP 首部,但不适用于内容本身(应用于内容的标头称为实体首部)。根据它们使用的上下文,通用标头可能是响应标头或请求标头;
- 响应首部:可以在 HTTP 响应中使用,并且不涉及该消息的内容。响应首部,如 Age、Location 或 Server 用于提供更详细的响应上下文。
- 表示首部:是一个 HTTP 标题描述的特定的表示,可能从请求返回的特定资源的不同版本。例如,相同的数据资源可能被格式化为 XML 或 JSON,然后该资源可能被编码为一种或多种压缩格式以供发送。客户端在内容协商期间指定他们喜欢的格式(使用Accept-*标头),表示首部告诉客户端他们实际收到的表示格式;
报文(主体)和实体(主体)的区别
HTTP 中与 HTTP 报文相关的容易混淆的两个概念就是:报文和实体。
- 报文(message):HTTP 通信中的基本单位,由 8 位组字节流(octet sequence)组成,通过 HTTP 协议通信传输;
- 实体(entity):作为请求或者响应的有效数据的补充项被传输,其内容由实体首部和实体主体组成;
报文也就是本文介绍的 HTTP 报文,实体其实就是请求和响应中传输的实体数据,例如 GET 请求中的查询字符串和 POST 请求中的提交的表单数据。
报文有报文主体,实体有实体主体,两者有什么区别吗?简单来说,HTTP 报文主体是用来传输请求和响应的实体主体的。
通常情况下,报文主体就等于实体主体。只有在 HTTP 传输中进行了编码操作,例如《如何在 Nginx 服务器中配置 GZip 压缩?》一文中介绍的,在服务端对响应内容进行了 gzip 编码压缩,这时响应首部报文的实体主体内容会发生变化,才会导致实体主体和报文主体产生差异。
Update:注意。当前的 HTTP/1.1 规范不再涉及实体、实体头或实体主体。某些字段现在称为表示首部字段。