【学习笔记】透视HTTP协议(七):HTTP报文详解

  本文是一篇学习笔记,学习的课程是极客时间的《透视HTTP协议》。

​​​​​​透视HTTP协议_HTTP_HTTPS-极客时间 (geekbang.org)

HTTP报文是HTTP协议交互的基础,它定义了客户端和服务器之间通信的规则和格式。请求报文由请求行、请求头部和请求体组成,用于向服务器发送请求;响应报文由状态行、响应头部和响应体组成,用于向客户端返回服务器的响应。通过合理地构建和使用HTTP报文,可以实现客户端和服务器之间的有效通信和数据传输。以下是关于HTTP报文的详细解释。

目录

一、报文结构

(1)报文结构说明

(2)完整的HTTP报文

(3)示例

二、请求行

三、状态行

四、头部字段(请求头和响应头)

(1)说明

(2)常用头字段

Host请求字段

User-Agent请求字段

Date字段

Server字段

Content-Length字段

五、总结


一、报文结构

(1)报文结构说明

HTTP协议的请求报文和响应报文的结构基本相同,由三大部分组成:

  1. 起始行(start line):描述请求或响应的基本信息;

  2. 头部字段集合(header):使用key-value形式更详细地说明报文;

  3. 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。

HTTP协议规定报文必须有header,但可以没有body,而且在header之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”。

(2)完整的HTTP报文

注意在header和body之间有一个“空行”。

(3)示例

在这个浏览器发出的请求报文里,第一行“GET / HTTP/1.1”就是请求行,而后面的“Host”“Connection”等等都属于header,报文的最后是一个空白行结束,没有body。

二、请求行

描述了客户端想要如何操作服务器端的资源

请求行由三部分构成:

  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. 状态码:一个三位数,用代码的形式表示处理的结果,比如200是成功,500是服务器错误;

  3. 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。

示例:

HTTP/1.1 200 OK

意思就是:“浏览器你好,我已经处理完了你的请求,这个报文使用的协议版本号是1.1,状态码是200,一切OK。”

四、头部字段(请求头和响应头

(1)说明

请求头和响应头的结构是基本一样的,唯一的区别是起始行,所以我把请求头和响应头里的字段放在一起介绍。

头部字段是key-value的形式,key和value之间用“:”分隔,最后用CRLF换行表示字段结束。比如在“Host: 127.0.0.1”这一行里key就是“Host”,value就是“127.0.0.1”。

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

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

  1. 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;

  2. 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;

  3. 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;

  4. 字段的顺序是没有意义的,可以任意排列不影响语义;

  5. 字段原则上不能重复,除非这个字段本身的语义允许,例如Set-Cookie。

(2)常用头字段

HTTP协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类:

  1. 通用字段:在请求头和响应头里都可以出现;

  2. 请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;

  3. 响应字段:仅能出现在响应头里,补充说明响应报文的信息;

  4. 实体字段:它实际上属于通用字段,但专门描述body的额外信息。

Host请求字段

Host字段,它属于请求字段,只能出现在请求头里,它同时也是唯一一个HTTP/1.1规范里要求必须出现的字段,也就是说,如果请求头里没有Host,那这就是一个错误的报文。

Host字段告诉服务器这个请求应该由哪个主机来处理,当一台计算机上托管了多个虚拟主机的时候,服务器端就需要用Host字段来选择,有点像是一个简单的“路由重定向”。

例如在125.1.123.1上有三个虚拟主机:“www.chrono.com”“www.metroid.net”和“origin.io”。那么当使用域名的方式访问时,就必须要用Host字段来区分这三个IP相同但域名不同的网站,否则服务器就会找不到合适的虚拟主机,无法处理。

User-Agent请求字段

User-Agent是请求字段,只出现在请求头里。它使用一个字符串来描述发起HTTP请求的客户端,服务器可以依据它来返回最合适此浏览器显示的页面。

有的比较“诚实”的爬虫会在User-Agent里用“spider”标明自己是爬虫,所以可以利用这个字段实现简单的反爬虫策略。

Date字段

Date字段是一个通用字段,但通常出现在响应头里,表示HTTP报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略。

Server字段

Server字段是响应字段,只能出现在响应头里。它告诉客户端当前正在提供Web服务的软件名称和版本号,例如“Server: openresty/1.15.8.1”。

Server字段也不是必须要出现的,因为这会把服务器的一部分信息暴露给外界,如果这个版本恰好存在bug,那么黑客就有可能利用bug攻陷服务器。所以,有的网站响应头里要么没有这个字段,要么就给出一个完全无关的描述信息。比如GitHub,它的Server字段里就看不出是使用了Apache还是Nginx,只是显示为“GitHub.com”。

Content-Length字段

Content-Length,它表示报文里body的长度,也就是请求头或响应头空行后面数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么body就是不定长的,需要使用chunked方式分段传输。

五、请求体

可选的,通常包含应用程序要传输到服务端的数据。

在POST或PUT请求中,请求体可能包含表单数据或JSON数据。

六、响应体

可选的,通常包含服务端返回的数据。

响应体可能包含HTML页面、JSON数据或其他类型的数据。

七、总结

  1. HTTP报文结构就像是“大头儿子”,由“起始行+头部+空行+实体”组成,简单地说就是“header+body”;

  2. HTTP报文可以没有body,但必须要有header,而且header后也必须要有空行,形象地说就是“大头”必须要带着“脖子”;

  3. 请求头由“请求行+头部字段”构成,响应头由“状态行+头部字段”构成;

  4. 请求行有三部分:请求方法,请求目标和版本号;

  5. 状态行也有三部分:版本号,状态码和原因字符串;

  6. 头部字段是key-value的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;

  7. HTTP/1.1里唯一要求必须提供的头字段是Host,它必须出现在请求头里,标记虚拟主机名。

如果拼HTTP报文的时候,在头字段后多加了一个CRLF,导致出现了一个空行,会发生什么?

在HTTP报文中,头字段(Header-field)与报文体(Message-body)之间通常是通过一个空行(CRLF,即回车符\r和换行符\n)来分隔的。如果在头字段后意外地多加了一个CRLF,即出现了一个额外的空行,可能会导致以下几种情况:

  1. 解析错误:HTTP客户端(如浏览器)或服务器在解析HTTP报文时,会根据CRLF来定位头字段和报文体。额外的CRLF可能会导致解析错误,使得客户端或服务器无法正确识别报文的各个部分。
  2. 还有别的情况吗?

讲头字段时说“:”后的空格可以有多个,那为什么绝大多数情况下都只使用一个空格呢?

  1. 可读性:一个空格足以清晰地分隔字段名和字段值,使得HTTP报文更加易读。过多的空格可能会增加报文的长度,降低可读性。

  2. 标准化:随着HTTP协议的发展,许多开发者和工具都遵循了一种标准化的做法,即在字段名和字段值之间只使用一个空格。这种标准化做法有助于减少误解和错误,并使得不同系统之间的交互更加顺畅。

  3. 历史原因:在HTTP协议发展的早期,许多实现都采用了只使用一个空格的做法。这种习惯被沿用至今,并成为了事实上的标准。

  4. 简洁性:HTTP协议本身追求简洁和高效。在字段名和字段值之间只使用一个空格可以减少报文的大小,提高传输效率。

  5. 兼容性:不同的HTTP客户端和服务器可能对空格的处理方式有所不同。为了兼容更多的系统和工具,使用一个空格作为标准做法可以减少潜在的问题和冲突。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值