Skip to main content

报文结构

前言:

HTTP 协议在规范文档里详细定义了报文的格式,规定了组成部分解析规则,还有处理策略,所以可以在 TCP/IP 层之上实现更灵活丰富的功能,例如连接控制,缓存管理、数据编码、内容协商等等。

HTTP 报文组成

HTTP 的报文可以分为请求报文响应报文两种,报文由起始行、头部、实体三部分组成,其中起始行和头部组成的部分又被称为请求头(请求报文)或响应头(响应报文)。

图:HTTP报文组成部分

由上图可知:

  • 起始行(start line):描述请求或响应的基本信息;
  • 头部(header):使用key-value 形式更详细地说明报文;
  • 实体(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

在很多时候,特别是浏览器发送 GET请求的时候都是这样,HTTP 报文经常是只有 header 而没 body。虽然 HTTP 协议对 header 的大小没有做限制,但各个 Web 服务器都不允许过大的请求头,因为头部太大可能会占用大量的服务器资源,影响运行效率。

起始行

由于 HTTP 报文分为请求报文和响应报文,所以起始行又可以细分为请求行和状态行,两者的组成略有不同。

请求行

了解了 HTTP 报文的基本结构后,我们来看看请求报文里的起始行也就是请求行(request line),它简要地描述了客户端想要如何操作服务器端的资源

请求行由以下三部分构成:

  1. 请求方法:GET/POST,表示对资源的操作;
  2. 请求目标:通常是一个 URI,标记了请求方法要操作的资源
  3. 版本号:表示报文使用的HTTP 协议版本

这三个部分通常使用空格(space)来分隔,最后要用 CRLF(回车换行)表示结束。

图:请求行

例如:

GET / HTTP/1.1

在这个请求行里,GET是请求方法,"/"是请求目标,HTTP/1.1是版本号,把这三部分连起来,意思就是“服务器你好,我想获取网站根目录下的默认文件,我用的协议版本号是 1.1,请不要用 1.0 或者 2.0 回复我。”

状态行

相对应请求报文中的请求行,响应报文里的起始行并不叫响应行,而是叫状态行(status line),意思是服务器响应的状态

状态行由以下三部分构成:

  1. 版本号:表示报文使用的 HTTP 协议版本;
  2. 状态码:一个三位数,用代码的形式表示处理的结果;
  3. 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。

图:状态行

例如:

HTTP/1.1 404 Not Found

状态行的意思就是:“抱歉啊浏览器,刚才你的请求收到了,但我没找到你要的资源错误代码是 404,接下来的事情你就看着办吧。

请求头和响应头

上面的内容提到,起始行和头部组成的部分又被称为请求头(请求报文)或响应头(响应报文)。头部字段是由一些具有特定含义的key-value组成。如下图所示:

图:请求头

图:响应头

由上图可知,请求头和响应头的结构是基本一样的,唯一的区别是起始行。而头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。比如在“Host: 127.0.0.1”这一行里 key 就是“Host”,value 就是“127.0.0.1”。

此外,HTTP 头字段是非常灵活的,不仅可以使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头,这就给 HTTP 协议带来了无限的扩展可能。

不过使用头字段需要注意下面几点:

  • 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
  • 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”和“test_name”是不正确的字段名;
  • 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;
  • 字段的顺序是没有意义的,可以任意排列不影响语义;
  • 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

对于头部常用的字段,我们将在下一章进行详解。