[趣谈网络协议学习] 14 HTTP协议:看个新闻原来这么麻烦

HTTP 协议,几乎是每个人上网用的第一个协议,例如http://www.163.com 是个 URL,叫作统一资源定位符。之所以叫统一,是因为它是有格式的。

  • HTTP 称为协议。
  • www.163.com 是一个域名,表示互联网上的一个位置。
  • 有的 URL 会有更详细的位置标识,例如 http://www.163.com/index.html 。

HTTP 请求的准备

浏览器会将 www.163.com 这个域名发送给 DNS 服务器,让它解析为 IP 地址,然后建立TCP连接(三次握手),目前使用的 HTTP 协议大部分都是 1.1,默认是开启了 Keep-Alive 的,这样建立的 TCP 连接,就可以在多次请求中复用。

HTTP 请求的构建

建立了连接以后,浏览器就要发送 HTTP 的请求
HTTP的请求格式
HTTP 的报文大概分为三大部分。第一部分是请求行,第二部分是请求的首部,第三部分才是请求的正文实体。

第一部分:请求行

由3部分组成,分别为:请求方法、URL 以及协议版本,之间由空格分隔

请求方法:包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的

议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1

HTTP1.1 中的请求方式:

方法作用
GET请求获取由 Request-URI 所标识的资源
POST请求服务器接收在请求中封装的实体,并将其作为由 Request-Line 中的 Request-URI 所标识的资源的一部分
HEAD请求获取由 Request-URI 所标识的资源的响应消息报头
PUT请求服务器存储一个资源,并用 Request-URI 作为其标识符
DELETE请求服务器删除由 Request-URI 所标识的资源
TRACE请求服务器回送到的请求信息,主要用于测试或诊断
CONNECT保留将来使用
OPTIONS请求查询服务器的性能,或者查询与资源相关的选项和需求

第二部分:首部字段

请求行下面就是首部字段。首部是 key value,通过冒号分隔。

常见请求头如下:

请求头说明
Host接受请求的服务器地址,可以是IP:端口号,也可以是域名
User-Agent发送请求的应用程序名称
Connection指定与连接相关的属性,如Connection:Keep-Alive
Accept-Charset通知服务端可以发送的编码格式
Contnet-Type正文的格式,如JSON
Cache-control控制缓存
If-Modified-Since如果服务器的资源在某个时间后更新了,客户端就应该下载最新下资源

第三部分:请求正文

可选部分,比如GET请求就没有请求正文

几个示例

GET请求示例:
GET请求示例
POST请求示例:
POST请求示例

HTTP 返回的构建

HTTP的返回报文格式

1,状态行

状态行由3部分组成,分别为:协议版本,状态码,短语,之间由空格分隔

状态码为3位数字反应HTTP请求的结果。200意味着大吉大利;404意味着服务端无法响应这个请求。
几个常见的状态码

状态码说明
200响应成功
301永久重定向,搜索引擎将删除源地址,保留重定向地址
302暂时重定向,重定向地址由响应头中的Location属性指定(JSP中Forward和Redirect之间的区别)由于搜索引擎的判定问题,较为复杂的URL容易被其它网站使用更为精简的URL及302重定向劫持
304缓存文件并未过期,还可继续使用,无需再次从服务端获取
400客户端请求有语法错误,不能被服务器识别
403服务器接收到请求,但是拒绝提供服务(认证失败)
404请求资源不存在
500服务器内部错误

短语大概说明一下原因。

2,响应头部

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

  • Retry-After:客户端应在多长时间后再次尝试一下。503指服务暂时不再和这个值配合使用。
  • Content-Type:可以是HTML,或JSON。

响应示例:
响应示例
构造好了返回的 HTTP 报文,接下来就是把这个报文发送出去。还是交给 Socket 去发送,还是交给 TCP 层,让 TCP 层将返回的 HTML,也分成一个个小的段,并且保证每个段都可靠到达。

HTTP 2.0

HTTP 1.1 在应用层以纯文本的形式进行通信。每次通信都要带完整的 HTTP 的头,而且不考虑 pipeline 模式的话,每次的过程总是像上面描述的那样一去一回。这样在实时性、并发性上都存在问题。

为了解决这些问题,HTTP 2.0通过头压缩、分帧、二进制编码、多路复用等提升性能。

  • 对HTTP的头进行一定的压缩,将原来每次都要携带的大量key value在两点建立一个索引表,对相同的头只发送索引表中的索引。
  • 将一个TCP的连接中,切分成多个流,每个流都有自己的ID。它是一个虚拟通道,有优先级。将所有传输信息分割为更小的消息和帧,并采用二进制编码。如Header帧,Data帧,多个Data帧属于同一个流。

通过这两种机制,HTTP 2.0 的客户端可以将多个请求分到不同的流中,然后将请求内容拆成帧,进行二进制传输。这些帧可以打散乱序发送, 然后根据每个帧首部的流标识符重新组装,并且可以根据优先级,决定优先处理哪个流的数据

举一个例子

假设我们的一个页面要发送三个独立的请求,一个获取 css,一个获取 js,一个获取图片 jpg。如果使用 HTTP 1.1 就是串行的,但是如果使用 HTTP2.0,就可以在一个连接里,客户端和服务端都可以同时发送多个请求或回应,而且不用按照顺序一对一对应。
HTTP2.0
HTTP 2.0 其实是将三个请求变成三个流,将数据分成帧,乱序发送到一个 TCP 连接中。

HTTP2.0

  • 成功解决了HTTP 1.1的队首阻塞问题,也不需要通过HTTP 1.x的pipeline机制用多条TCP连接实行并行请求与响应;
  • 减少了 TCP连接数对服务器性能的影响,同时将页面的多个数据 css、js、 jpg 等通过一个数据链接进行传输,能够加快页面组件的传输速度。

QUIC 协议的"城会玩"

HTTP 2.0 虽然大大增加了并发性,但还是有问题的。因为 HTTP 2.0 也是基于 TCP 协议的,TCP 协议在处理包时是有严格顺序的。当其中一个数据包遇到问题,TCP 连接需要等待这个包完成重传之后才能继续进行。前面的stream 2的帧没有收到,后面的stream 1也会阻塞。

QUIC 通过UDP,自定义类似的TCP的连接、重试、多路复用、流量控制,进一步提升性能。

Google 的 QUIC 协议,它是如何“城会玩”的。

机制一:自定义连接机制

基于UDP,在QUIC自己的逻辑中维护连接的机制,不再以四元组标识,以64位的随机数作为ID来标识。 UDP 是无连接的,所以当 IP 或者端口变化的时候,只要 ID 不变,就不需要重新建立连接。

机制二:自定义重传机制

QUIC 也有个序列号,是递增的。任何一个序列号的包只发送一次,下次就要加一了。例如,发送一个包,序号是 100,发现没有返回;再次发送的时候,序号就是 101 了;如果返回的 ACK 100,就是对第一个包的响应。如果返回 ACK 101 就是对第二个包的响应,RTT 计算相对准确。

但是这里有一个问题,就是怎么知道包 100 和包 101 发送的是同样的内容呢?QUIC 定义了一个 offset 概念。

QUIC 既然是面向连接的,也就像 TCP一样,是一个数据流,发送的数据在这个数据流里面有个偏移量 offset,可以通过 offset 查看数据发送到了哪里,这样只要这个 offset 的包没有来,就要重发;如果来了,按照 offset 拼接,还是能够拼成一个流。

自定义重传机制
图中 左边原TCP重传,右边QUIC重传

机制三:无阻塞的多路复用

同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求。但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖。这样,假如 stream2 丢了一个 UDP 包,后面跟着 stream3 的一个 UDP 包,虽然 stream2 的那个包需要重传,但是 stream3 的包无需等待,就可以发给用户。

机制四:自定义流量控制

TCP 的流量控制是通过滑动窗口协议。

QUIC 的流量控制也是通过 window_update,来告诉对端它可以接受的字节数。但是 QUIC 的窗口是适应自己的多路复用机制的,不但在一个连接上控制窗口,还在一个连接中的每个 stream 控制窗口。

QUIC 的 ACK 是基于 offset 的,每个 offset 的包来了,进了缓存,就可以应答,应答后就不会重发,中间的空挡会等待到来或者重发即可,而窗口的起始位置为当前收到的最大 offset,从这个 offset 到当前的 stream 所能容纳的最大缓存,是真正的窗口大小。显然,这样更加准确。
自定义流量控制

另外,还有整个连接的窗口,需要对于所有的 stream 的窗口做一个统计

小结

  • HTTP 协议虽然很常用,也很复杂,重点记住 GET、POST、 PUT、DELETE 这几个方法,以及重要的首部字段;
  • HTTP 2.0 通过头压缩、分帧、二进制编码、多路复用等技术提升性能;
  • QUIC 协议通过基于 UDP 自定义的类似 TCP 的连接、重试、多路复用、流量控制技术,进一步提升性能。

参考资料:

趣谈网络协议(极客时间)链接:
http://gk.link/a/106nW

HTTP基本原理(格式详解):
https://blog.csdn.net/hudashi/article/details/50789006

HTTP请求、响应报文格式:
https://blog.csdn.net/a19881029/article/details/14002273


GitHub链接:
https://github.com/lichangke/LeetCode
知乎个人首页:
https://www.zhihu.com/people/lichangke/
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值