Web Server 101: HTTP 报文解析


学习笔记,非纯原创

HTTP (HyperText Transfer Protocol,超文本传输协议) 是基于 TCP 的应用层协议,通信方式是 client / server 模式。HTTP 报文 (HTTP packet) 分为两种:请求报文(request packet)回复报文(response packet)

1. 请求报文

请求报文由客户向服务器发送,报文由三个部分组成,即请求行、首部行和实体主体。

请求报文结构

CRLF: 回车换行 1
CRLFCarriage-Return Line-Feed 的缩写,意思是回车换行。http 请求报文每行都是 CRLF 结尾。
在 C 语言编程中,回车 (\r) 和换行 (\n) 使用时的主要区别在于

  • \r 会回到当前行的行首,如果接着输出的话,本行旧的内容会被覆盖
  • \n 将光标转到下一行的起始位置,不会回到行首

二者的出现要回溯到计算机还没有出现之前,有一种叫做电传打字机的外设,每秒钟可以打 10 个字符。但是它有一个问题,就是打完一行换行的时候,要用去 0.2 秒,正好可以打两个字符。要是在这 0.2 秒里面,又有新的字符传过来,那么这个字符将丢失。

于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符,即为回车 (carriage return) — 告诉打字机把打印头定位在左边界,换行 (line feed) - 告诉打字机把纸向下移一行。

计算机发明后,这两个概念也就被搬到了计算机上。那时存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是就出现了分歧:

  • Unix 系统里,每行结尾只有 \n
  • Windows 系统里面,每行结尾是 \n\r
  • Mac 系统里,每行结尾是 \r。

一个直接后果是,Unix/Mac 系统下的文件在 Windows 里打开的话,所有文字会变成一行;而 Windows 里的文件在 Unix/Mac 下打开的话,在每行的结尾可能会多出一个 ^M 符号。

1.1. 请求行

请求报文的开始行称为请求行,包含请求方法、请求 URL 和 HTTP 版本三个字段。每个字段都以空格分隔。 比如:GET / HTTP/1.1,请求方法为 GET,请求 URL 为/,HTTP 版本为 HTTP/1.1

方法就是对所请求的对象进行的操作,实际上就是一些命令。因此请求报文的类型是由它所采用的方法决定的。

请求报文的一些方法

  • GET:当客户端要从服务器中读取文档时,使用 GET 方法请求读取由 URL 所标志的信息。使用 GET 方法时,请求参数和对应的值附加在 URL 后面,利用一个问号 “?” 代表 URL 的结尾与请求参数的开始,传递参数长度受限制。例如,/index.jsp?id=100&op=bind
  • POST:当客户端给服务器提供信息较多时可以使用 POST 方法。POST 方法将请求参数封装在 HTTP 请求数据中,以名称 / 值的形式出现,可以传输大量数据。
  • HEAD:请求读取由 URL 所标志的信息的首部
  • DELETE: 删除指明的 URL所标志的资源

GET 和 POST 的区别

  1. GET没有body,POST有body,body中有若干字符串,首部行中的Content_Length标记着body的长度
  2. GET不安全,POST比较安全
  3. GET的参数长度有限制,而POST的参数长度没有限制,是因为 GET 的参数在URL中,而 POST 的参数是在实体主体中
  4. GET的参数可见,POST的参数不可见

1.2. 首部行

首部行包含用于说明浏览器、服务器或报文主体的一些信息,以键值对的形式存储。整个首部行结束时,还有一个空行将首部行和后面的实体主题分开。

首部行中的一些字段

  • Content-Length: 标记着body的长度,
  • User-Agent: 标记浏览器类型和操作系统的版本
  • Contet-Type: 标记着数据类型(text/html等)
  • Host: 客户端告知服务器,所请求的资源是在哪个主机的那个端口上
  • Cookie: 用于在客户端存储少量信息,通常用于实现会话(session)功能
  • Accept-Language: 标记着用户所使用的语言
  • Keep-Alive:time:标记着连接的时间
  • Connection:close 此时表示是非持久连接
  • Connection:keep-alive 此时表示是持久连接

1.3. 实例

下面是一个完整的 HTTP 请求报文实例。其中请求行使用了相对 URL(省略了主机域名)是因为 Host 首部行给出了主机域名。

一般请求报文不使用实体主体。

GET /dir/index.htm HTTP/1.1  # 请求行使用了相对URL
Host: www.xyz.edu.cn         # 首部行的开始,给出了主机的域名
Connection: close            # 告诉服务器传送完请求的对象后就关闭 TCP 连接
User-Agent: Mozilla/5.0      # 表明用户代理是使用火狐浏览器
Accept-Languag: cn           # 表明用户优先得到中文版本的文档
                             # 请求报文的最后还有一个空行,标识首部行的结束

2. 回复报文

响应报文结构

2.1. 状态行

响应报文是服务器给客户端发送的,用来回复客户端的请求。第一行称为状态行,包含 HTTP 版本、状态码(status code)以及描述操作状态的原因短语。
比如:HTTP/1.1 200 OK。 HTTP 版本为 HTTP/1.1,数字状态码是 200,原因短语是 OK,表示请求成功。

状态码
状态码都是三位数字的,分为 5 大类:

  • 1XX:通知信息,服务器收到请求,需要请求者继续执行操作
  • 2XX:成功,操作被成功接收并处理
  • 3XX:重定向,需要进一步的操作以完成请求
  • 4XX:客户端错误,请求包含语法错误或无法完成请求
  • 5XX:服务器错误,服务器在处理请求的过程中发生了错误

2.2. 响应头部

与请求头部类似,为响应报文添加了一些附加信息。

常见响应头部

  • Server:服务器应用程序软件的名称和版本
  • Content-Type:响应正文的类型(是图片还是二进制字符串)
  • Content-Length:响应正文长度
  • Content-Charset:响应正文使用的编码
  • Content-Encoding:响应正文使用的数据压缩格式
  • Content-Language:响应正文使用的语言

2.3. 实例

下面是一个http 报文实例,可以注意到,在实体主体部分返回了请求的页面

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Closed

<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>

3. 参考资料

  1. TinyHTTPd 源码分析
  2. httpserver–如何解析HTTP请求报文
  3. 谢希仁.计算机网络 (第七版)(2017).

文章作者: Shane Tsui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Shane Tsui !

  目录