HTTP 协议与 TCP/UDP 类似,需要在实际传输的数据前附加一些头数据。不过与 TCP/UDP 不同的是,HTTP 协议是一个“纯文本”协议,头部数据都是 ASCII 码的文本,可以直接阅读。
报文结构
HTTP 协议的请求报文和响应报文基本相同,由三大部分组成:
- 起始行(start line):描述请求和响应的基本信息;
- 头部字段集合(header):使用 key-value 形式更详细的说明报文;
- 消息正文(entity):实际传输的数据,可以是文本、图片、视频等。
其中前两部分起始行和头部字段经常合称为“请求头”或“响应头”,消息正文又称为“body”。
HTTP 协议规定报文必须有 header,可以没有 body,而且在 header 之后必须要有一个“空行(CRLF)”。
请求行
GET / HTTP/1.1
请求行由三部分构成:
- 请求方法:如 GET、POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
这三部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。
状态行
HTTP/1.1 200 OK
响应报文中的起始行称为“状态行”,意思是服务器响应的状态。
状态行也是由三部分构成:
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,表示处理的结果。如 200 是成功,500 是服务器错误。
- 原因:作为数字状态码补充,是更详细的解释。
头部字段
请求行或状态行再加上头部字段集合就构成了 HTTP 报文里完整的请求头或响应头。
头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。
HTTP 头字段非常灵活,不仅可以使用标准里的 Host、Connection 等已有头,还可以任意添加自定义头,这给 HTTP 协议带来了无限拓展可能。
常用头字段
基本可以分为四大类:
- 通用字段:在请求头和响应头里都可以出现;
- 请求字段:只能出现在请求头里,进一步说明请求信息或额外的附加条件;
- 响应字段:只能出现在响应头里,补充说明响应报文的信息;
- 实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。
Host
Host 属于请求字段,只能出现在请求头里,同时也是唯一一个 HTTP/1.1 规范里要求必须出现的字段。
Host 字段告诉服务器这个请求该由哪个主机来处理,当一台计算机上托管了多个虚拟主机的时候,服务器端就需要用 Host 字段来选择,有点像一个简单的“路由重定向”。
User-Agent
User-Agent 属于请求字段,只出现在请求头里。描述发起 HTTP 请求的客户端,服务器可以依据它来返回最适合此浏览器显示的页面。
Date
Date 是一个通用字段,但通常出现在响应头里,表示 HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略。
Server
Server 是响应字段,只能出现在响应头里。它告诉客户端当前正在提供 Web 服务的软件名称和版本号。这个字段不是必须要出现的,因为这会把服务器的一部分信息暴露给外界。所以,有的网站响应头里要么没有这个字段,要么就给出一个完全无关的信息。
Content-length
Content-length 表示报文里 body 的长度,也就是请求头或响应头空行后面数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么 body 就是不定长的,需要使用 chunked 方式分段传输。
问题:
-
如果在拼 HTTP 报文的时候,在头字段后多加了一个 CRLF,导致出现了一个空行,会发生什么?
答:在 header 下面第一个空行以后都会被当作 body 处理 -
头字段“:”后面的空格可以有多个,那么为什么绝大多数情况下都只使用一个空格呢?
答:头部多一个空格就会多一个传输的字节,去掉无用的信息,保证传输的头部字节数尽量小。