HTTP 协议入门
早上看了阮一峰老师写的 " HTTP 协议入门 ",总结一下。
一、HTTP
HTTP 协议(无状态协议)是基于 TCP/IP 协议的应用层协议,规定了客户端与服务端的通信格式,一般用 80 端口。
无状态:减少服务器的 CPU 及内存资源的消耗。但是不对之前发生过的请求和响应的状态进行管理。
解决方法:引入 Cookie。客户端首次发送请求,收到响应报文内的叫做 Set-Cookie 的首部字段信息,保存 Cookie,下次请求时,自动在请求报文中加入 Cookie 值后发送出去。服务器端收到 Cookie,检查是从哪个客户端发来的请求,对比记录,得到之前的状态信息。
HTTP 的缺点
- 通信使用明文,内容可能被窃听
- 不验证通信双方的身份,可能遭遇伪装
- 无法证明报文的完整性,可能造篡改
为什么不一直使用 HTTPS
因为与纯文本通信对比,加密通信会消耗更多的 CPU 及内存资源。所以,非敏感信息使用 HTTP 通信。
二、HTTP/0.9
- 1991 年 5 月发布,只有一个 GET 命令。
- 服务端只能回复 HTML 格式的字符串,并且发送回应之后就关闭 TCP 连接。
三、HTTP/1.0
- 1996 年发布,增加了 POST 命令和 HEAD 命令。
- 任何格式的内容都可以传输,包括图像,视频二进制文件等。
- 请求和回应的格式:除了数据部分,增加头文件,描述元数据
- 另外增加的部分:状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。
请求格式
GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
回应格式
HTTP/1.0 200 OK //协议版本 + 状态码(status code) + 状态描述
Content-Type: text/plain //回应的数据的格式,可以自定义类型
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>Hello World</body>
</html>
缺点
每个 TCP 连接只能发送一个请求,发送数据完成之后连接就关闭,如果还想请求其他的资源,必须重新建立新的 TCP 连接。
解决该缺点的一个方法
有的浏览器在请求的时候,使用 Connection 字段,要求服务器不关闭 TCP 连接,以便其他请求复用,服务器同样回应同样的字段:
Connection: keep-alive
四、HTTP/1.1
- 1997 年 1 月发布。
- 增加了持久连接(persistent connection),客户端和服务器在一段时间没有活动就关闭连接,规范的做法是:在最后一个请求是加入" Connection: close " 字段,明确请求服务器关闭 TCP 连接。
- 增加管道机制(pipelining),在用一个 TCP 连接里,客户端可以同时发送多个请求。但是服务器还是按照顺序回应请求。
- " Content-Length: 3495 " 字段,用来区分该数据属于哪个回应,例如本次回应 3496 个字节,后面的字节属于下一个回应。但是前提条件是,服务器发送回应之前,必须知道回应的数据长度。
- 分块传输编码(chunked transfer encoding):"
Transfer-Encoding: chunked " 字段。在每个数据块之前都有一个16进制的数值,表示此块的长度,最后一个数据块长度为 0,这样就不需要 Content-Length 字段来表示属于哪个回应。
缺点
虽然可以同时发送请求,但是服务器的回应依然是按照次序进行的,所以可能造成 “ 队头堵塞 ”。
解决方法
1、减少请求数
2、同时多开持久连接,每个请求分开在不同的 TCP 连接里
五、HTTP/2
- 2015 年发布。不是 2.0 版本,因为不准备发布子版本。
- 二进制协议:头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
- 多工:双向、同时的通信,在同一个连接里,客户端和浏览器都可以同时发送多个请求或回应,避免了"队头堵塞"。如果当前请求时间过长,先发送已处理好的部分,回应下一个请求,完成后再继续回应上一个请求。
- 数据流(stream):每个请求或回应的所有数据包。每个数据流都有一个独一无二的编号,数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。而且,数据流发送中途,客户端和服务端都可以发送信号来取消这个数据流,并且不断开 TCP 连接。
- 头信息压缩:请求的很多字段都是重复的,浪费带宽,所以,头信息使用
gzip
或compress
压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。 - 服务器推送(server push):服务器未经请求,主动向客户端发送资源
同时,在评论区看到了一个人问的问题,我回复了自己的看法,更加深了对 HTTP 的理解。
参考资料:HTTP 协议入门
我理解是这样:管道机制下,在同一个时间点,tcp 包含多个请求,但是这些请求有先后的顺序(即使看起来好像是客户端同时发出的,但还是有先后顺序的),服务端在回应的时候就按照这种顺序一一回应。
在您说的里面,应该是按照次序回应请求,而不是发送请求。
个人理解。