作为前端工程师,需要了解一些 HTTP 协议的相关知识。例如在查看分析 network 标签中返回的响应数据的时候,我们就需要了解 HTTP 报文的数据结构,以便我们分析定位网络请求的问题。本文就是专门介绍 HTTP 报文相关知识的。
HTTP 报文简介
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);
ini
# 请求行
GET /blog/understanding-uri-and-url/ HTTP/1.1
# 首部字段
Host: www.yaohaixiao.com
Proxy-Connection: keep-alive
Cache-Control: max-age=0
# 空行(CR + LF)
# 其它
Cookie: Hm_lvt_cebfb56d60d4947826afe73a03c2=1623122954;
请求首部字段的类型
请求首部字段主要有 3 类类型:通用首部、请求首部、实体首部。
- 通用首部: 过时的术语,当前版本的 HTTP/1.1 规范并未将标头明确归类为"通用标头"。用于指可在请求和响应消息中使用的 HTTP 首部,但不适用于内容本身(应用于内容的标头称为实体首部)。根据它们使用的上下文,通用标头可能是响应标头或请求标头;
- 请求首部: 提供关于该请求的上下文信息,以便服务器可以定制响应。并非所有可以出现在请求中的标头都被规范称为请求标头。例如,Content-Type 标题被称为表示首部。;
- 表示首部: 是一个 HTTP 标题描述的特定的表示,可能从请求返回的特定资源的不同版本。例如,相同的数据资源可能被格式化为 XML 或 JSON,然后该资源可能被编码为一种或多种压缩格式以供发送。客户端在内容协商期间指定他们喜欢的格式(使用Accept-*标头),表示首部告诉客户端他们实际收到的表示格式;;
响应首部的结构
响应报文首部的内容组成:
- 状态行:包含表明相应结果的状态码、原因短语和 HTTP 版本;
- 首部字段:包含表示请求的各个条件和属性的各类首部;
- 其它:可能包含 HTTP 的 RFC 里 未定义的首部(如 Cookie);
xml
# 状态行
HTTP/1.1 200 OK
# 相应首部
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 传输中进行了编码操作,例如《前端性能优化 - 启用 Gzip 压缩》一文中介绍的,在服务端对响应内容进行了 gzip 编码压缩,这时响应首部报文的实体主体内容会发生变化,才会导致实体主体和报文主体产生差异。
注意: 当前的 HTTP/1.1 规范不再涉及实体、实体头或实体主体。某些字段现在称为表示首部字段。
最后希望在阅读完本文之后,在你分析 HTTP 请求响应信息的时候,你能清晰知道 HTTP 报文中的信息,也能根据请求和响应信息分析定位出问题。