写点什么

http 协议

作者:en
  • 2021 年 12 月 05 日
  • 本文字数:2916 字

    阅读完需:约 10 分钟

http协议

前言

http 协议的学习总结

一.http 协议

1.1 简介

HTTP(超文本传输协议)是一个 client-server 请求和应答的标准。

1.2 建立流程

  1. 客户端建立一条 TCP 连接(如果传输层不是 TCP,也可以是其他适合的连接)。

  2. 客户端发送请求并等待应答。

  3. 服务器处理请求并送回应答,回应包括一个状态码和对应的数据。

1.3 http 协议变迁

1.3.1 HTTP/0.9

最初最简单的协议,只支持 GET 方法,只可以传输 HTML 文件;没有其他状态码或错误代码;出现问题会返回一个特殊的包含问题描述信息的 HTML 文件。

1.3.2 HTTP/1.0 - 构建可拓展性

优化点

由于 HTTP/0.9 协议的应用十分有限,浏览器和服务器迅速扩展内容使其用途更广:

  • 协议版本信息现在会随着每个请求发送(HTTP/1.0被追加到了GET行)。

  • 状态码会在响应开始时发送,使浏览器能了解请求执行成功或失败,并相应调整行为(如更新或使用本地缓存)。

  • 引入了 HTTP 头的概念,无论是对于请求还是响应,允许传输元数据,使协议变得非常灵活,更具扩展性。

  • 在新 HTTP 头的帮助下,具备了传输除纯文本 HTML 文件以外其他类型文档的能力(感谢Content-Type头)。

缺点

1.默认短链接:导致每次与服务器交互都要新开一个连接,重新经历三次握手,四次挥手,慢启动

2.发送一次请求,要等待服务端响应才可以继续发送

1.3.3 HTTP/1.1 – 标准化的协议

优化点

  • 连接可以复用,节省了多次打开 TCP 连接加载网页文档资源的时间。

  • 增加管线化技术,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。

  • 实现断点续传:利用 http 消息头使用分块传输编码,将实体主体分块传输

  • 引入额外的缓存控制机制。

  • 引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换。

  • 感谢Host头,能够使不同域名配置在同一个 IP 地址的服务器上。


缺点

1.管线化技术只是理论可行,实际上大部分都是关闭,还是一个请求一个响应的方式进行数据交互

2.HTTP 头部巨大且重复,由于 HTTP 协议是无状态的(如果需要上下文就需要在 header 的 cookies 里面携带额外信息),每一个请求都得携带 HTTP 头部,特别是对于有携带 cookie 的头部,而 cookie 的大小通常很大;

3.不支持服务器推送消息,因此当客户端需要获取通知时,只能通过定时器不断地拉取消息,这无疑浪费大量了带宽和服务器资源。

1.3.3 HTTP/2.0 – 性能的优化

头部压缩

http/1.1 的 header 中存在问题如下:

  • 含很多固定的字段,比如 Cookie、User Agent、Accept 等,这些字段加起来也高达几百字节甚至上千字节,所以有必要压缩

  • 大量的请求和响应的报文里有很多字段值都是重复的,这样会使得大量带宽被这些冗余的数据占用了,所以有必须要避免重复性

  • 字段是 ASCII 编码的,虽然易于人类观察,但效率低,所以有必要改成二进制编码

基于以上缺陷,htto/2.0 通过 HPACK 算法压缩同步,同时以二进制编码传输

二进制帧

HTTP/2 厉害的地方在于将 HTTP/1 的文本格式改成二进制格式传输数据,极大提高了 HTTP 传输效率,而且二进制数据使用位运算能高效解析。

你可以从下图看到,HTTP/1.1 的响应 和 HTTP/2 的区别:



HTTP/2 把响应报文划分成了两个帧(Frame,图中的 HEADERS(首部)和 DATA(消息负载) 是帧的类型,也就是说一条 HTTP 响应,划分成了两个帧来传输,并且采用二进制来编码。

HTTP/2 二进制帧的结构如下图:



帧头(Fream Header)很小,只有 9 个字节,帧开头的前 3 个字节表示帧数据(Fream Playload)的长度

帧长度后面的一个字节是表示帧的类型,HTTP/2 总共定义了 10 种类型的帧,一般分为数据帧控制帧两类,如下表格:



帧类型后面的一个字节是标志位,可以保存 8 个标志位,用于携带简单的控制信息,比如:

  • END_HEADERS 表示头数据结束标志,相当于 HTTP/1 里头后的空行(“\r\n”);

  • END_STREAM 表示单方向数据发送结束,后续不会再有数据帧。

  • PRIORITY 表示流的优先级;

帧头的最后 4 个字节是流标识符(Stream ID),但最高位被保留不用,只有 31 位可以使用,因此流标识符的最大值是 2^31,大约是 21 亿,它的作用是用来标识该 Fream 属于哪个 Stream,接收方可以根据这个信息从乱序的帧里找到相同 Stream ID 的帧,从而有序组装信息。

最后面就是帧数据了,它存放的是通过 HPACK 算法压缩过的 HTTP 头部和包体。

并发传输

不同于 http/1.1 一次请求一个响应的方式,http/2.0 支持并发传输,要搞清楚并发传输的实现,首先等弄懂如下三个概念:Stream,Message,Frame

一个 tcp 连接中包含多个 Stream(并发实现关键)

Stream 里可以包含 1 个或多个 MessageMessage 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成;

Message 里包含一条或者多个 FrameFrame 是 HTTP/2 最小单位,以二进制压缩格式存放 HTTP/1 中的内容(头部和包体)

以上的交互方式表明了:HTTP 消息可以由多个 Frame 构成,以及 1 个 Frame 可以由多个 TCP 报文构成。

在 HTTP/2 连接上,不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream ),因为每个帧的头部会携带 Stream ID 信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息,而同一 Stream 内部的帧必须是严格有序的

客户端和服务器双方都可以建立 Stream, Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号(用于推送资源)。

同一个连接中的 Stream ID 是不能复用的,只能顺序递增,所以当 Stream ID 耗尽时,需要发一个控制帧 GOAWAY,用来关闭 TCP 连接。

在 Nginx 中,可以通过 http2_max_concurrent_streams 配置来设置 Stream 的上限,默认是 128 个。

HTTP/2 通过 Stream 实现的并发,比 HTTP/1.1 通过 TCP 连接实现并发要牛逼的多,因为当 HTTP/2 实现 100 个并发 Stream 时,只需要建立一次 TCP 连接,而 HTTP/1.1 需要建立 100 个 TCP 连接,每个 TCP 连接都要经过 TCP 握手、慢启动以及 TLS 握手过程,这些都是很耗时的。

服务器主动推送资源

HTTP/1.1 不支持服务器主动推送资源给客户端,都是由客户端向服务器发起请求后,才能获取到服务器响应的资源。

比如,客户端通过 HTTP/1.1 请求从服务器那获取到了 HTML 文件,而 HTML 可能还需要依赖 CSS 来渲染页面,这时客户端还要再发起获取 CSS 文件的请求,需要两次消息往返,如下图左边部分:



如上图右边部分,在 HTTP/2 中,客户端在访问 HTML 时,服务器可以直接主动推送 CSS 文件,减少了消息传递的次数。

在 Nginx 中,如果你希望客户端访问 /test.html 时,服务器直接推送 /test.css,那么可以这么配置:

location /test.html {   http2_push /test.css; }
复制代码


客户端发起的请求,必须使用的是奇数号 Stream,服务器主动的推送,使用的是偶数号 Stream。服务器在推送资源时,会通过 PUSH_PROMISE 帧传输 HTTP 头部,并通过帧中的 Promised Stream ID 字段告知客户端,接下来会在哪个偶数号 Stream 中发送包体。



如上图,在 Stream 1 中通知客户端 CSS 资源即将到来,然后在 Stream 2 中发送 CSS 资源,注意 Stream 1 和 2 是可以并发的。


二.rpc(Remote Procedure Call)协议


参考文档

http

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Session

https://blog.csdn.net/weixin_38087538/article/details/82838762

https://www.zhihu.com/question/306768582(小林 coding

发布于: 19 分钟前阅读数: 3
用户头像

en

关注

努力分享对他人有价值的知识 2018.06.14 加入

还未添加个人简介

评论

发布
暂无评论
http协议