美文网首页
那些年,我们一起追的HTTP协议……

那些年,我们一起追的HTTP协议……

作者: flycash | 来源:发表于2019-01-06 17:46 被阅读18次

最近刷公众号突然刷到了HTTP3的消息下一代HTTP底层协议将弃用TCP协议 改用QUIC技术。想起前几天才和人家吹完HTTP2的牛逼,明明刚刚站在时代浪潮前面,结果又一个后浪把我脚下的前浪拍死在岸边了。

程序员三十几岁难混不是没理由的,毕竟总有一些人喜欢搞些新科技,稍不留神,就成了老古董了。

今天这篇文章,就是随便聊聊HTTP。

HTTP1.0-> HTTP2

为了理解HTTP3的改进,或者说我们为什么要搞一个新的HTTP协议,得先回顾一下HTTP诞生到现在的升级打怪历程。

倔强青铜-HTTP1.0

虽然,万维网(World Wide Web)早就出来了,但是HTTP第一份标准协议出来的时候,是在1991年,那年我还没出生,邓小平也还没南巡。那时候HTTP连1.0都没有,只叫做HTTP0.9。

这个HTTP非常的原始,刚出新手村,操作原始,铭文简陋。不过考虑到那个时候的个人电脑和网络带宽,这个原始的HTTP还是工作良好的。

后来,Dave Raggett领导的HTTP Working Group就觉得HTTP0.9太菜了,不好使,就给HTTP0.9升了个级。这次升级现在看来也是小打小闹,就是在原本0.9的基础上扩展了不同的method, headers,还有一些meta数据。完成这个扩展之后,他们就发布了HTTP1.0的RFC1945

现在,HTTP协议才算是走出了新手村,可以在江湖里面使劲浪了。

秩序白银-HTTP1.1

在HTTP1.0出来不就之后,大家就发现了一些问题,感觉主角还是太弱了。这个角色弱在哪里呢?

  1. 缓存太垃圾了。相当于铭文太低级了,虽然有铭文,但是都是一些2,3级的铭文,有个蛋用;
  2. Host支持。那时候假设的都是Host和ip是一一映射关系,相当于对战里面的英雄是不允许重复的,没想到后来来了克隆模式;
  3. 不支持长连接,每次请求都得新建TCP连接。也就是续航太差,每次团完都得回家,不能做到“我在外面使劲浪,回家算我输”;
  4. 请求都需要得到响应之后才能继续下一个请求。这就是,团战只能先砍死一个人,才能砍下一个,肯定要完蛋。HTTP需要的是强力AOP技能,一打打一片,砍人砍全家;

缓存

我觉得第一个要拎出来说的就是缓存支持不好。这是一个很奇怪的事情。站在现在的角度省视那个年代的设计,其实很难理解,在那样一个带宽低下的年代,设计者竟然没有把缓存当成一个非常重要的特征来考虑。所以,HTTP1.1就加强了对缓存的支持,引入了If-Match,If-None-Match,If-Unmodified-Since等头部;

Host支持

第二个要说的改进是Host支持。HTTP1.0有一个假设,就是一个服务器绑定一个ip地址。我觉得这个假设和ipv4一样有趣。在这个假设之下,HTTP1.0就没有要求传递主机名,也就是Host。然后就是刚发布完HTTP1.0之后他们就觉得这个假设不太靠谱,于是在HTTP1.1里面就增加了这个支持,允许请求里面带上Host。现在我们的nginx里面的http的配置,很多都是根据Host,也就是server_name来分发的。所以这个字段的重要性真是不言而喻。

长连接(Persistent Connection)和请求流水线(Pipeline)

长连接这个东西看起来更加像是语法糖,而不是HTTP协议的本质特征。我们先回顾一下,长连接出现的背景。

HTTP早期的设计是非常简洁的,非常优雅的——至少和现在比起来,要简洁优雅很多,虽然原始一点。即,HTTP认为浏览器和服务器只需要保持短暂的连接,一个请求过去,得到响应,而后就断开连接。服务器并不需要跟踪用户,也不需要记录状态。这就是我所认为的优雅和简洁。

但是,这个东西在实际运用中就有坑了。最大的坑就是HTTP依赖于TCP连接,而TCP的连接创建过程是非常慢的,甚至于会比数据传输还要慢。这其实并不能算是HTTP自身的缺点,而只能算是遇人不淑了。于是长连接应运而生,就是保持连接。在一个请求-响应结束之后并不立刻断开连接,而是由双方通过HTTP头部来协商什么时候断开连接。

而所谓流水线,不过是长连接产生之后自然而然出现的。即客户端可以通过一个连接发出多个请求,而摒弃了原本一个请求只有得到相应之后,才能继续下一个请求的“原则”。

这个设计,怎么说呢,我一直觉得就是一个语法糖,而且并不是特别优雅,也不够简洁。它在HTTP协议层面上加了很多的乱七八糟的东西,为了支持这个HTTP协议,需要做更加多的事情。而HTTP无状态的这个设计,我也觉得足够的纯粹,只是不太好用而已。所以又有了一大堆的cookie什么的东西。

优雅简洁的东西,没几个好用的。

小结

HTTP1.1还扩展支持了Range Request, Conditional Request, Authentication。这几个在实际中也很常用,尤其是前面的两个。

无论如何,HTTP1.1还是面世了。虽然它的第一个规范RFC2068发布在1997年,不过直到2014年,还发布了更新后的规范,这个更新直接将HTTP1.1分成了六个部分:

实际上,就现在来说,绝大部分网站还是在使用HTTP1.1,偶尔还得兼容一下HTTP1.0。比如说面试在谈及HTTP的时候,绝大部分人讨论的特征,都是HTTP1.1的特征。打开网站,去看协议版本,也是HTTP1.1占据大多数。

我觉得和HTTP长达十几年的停滞是分不开的。虽然不知道中间出了什么幺蛾子,但是在1997-2014年中,HTTP竟然没有大的更新,绝对是一个很不正常的事情。

在这十几年的停滞里,哥读完了小学,中学,高中,连本科都毕业了。

荣耀黄金——SPDY

事情的转机出现在谷歌。谷歌这个玩家,看不上那个挫逼HTTP1.1,技术差,意识差。于是他们闭关修炼了几个月之后,搞出来了一个SPDY。这个SPDY其实就是为了搞一件事:(提高手速)提高页面加载速度,降低延迟。

SPDY这个东西呢,其实并不是用于替代HTTP的,只是HTTP的增强版。其关键点就是,请求优先级,数据多路复用。请求优先级这个很好理解,就好比,你开团的时候,肯定会先把鲁班砍死……这个就是优先级:有些英雄比较讨厌,你会先弄死它。
而数据的多路复用,这个东西就是属于“人所共知的理念“,比如Redis的IO多路复用,比如NIO。通俗来说,就是只用一个tcp连接来连接一个客户端,所有和该客户端的通信都在该连接上。注意的一个区别是,HTTP1.1虽然支持长连接,但是本质上来说,并没有强制要求只建立一个TCP连接,而是浏览器你开心就好……

SPDY的理念是极好的,但是实际效果呢稍微差了一点,所以后来即便主流浏览器都支持,但是并没有得到大规模的应用。

可见,即便是谷歌这种骨灰级玩家,研究出来的套路,也不一定大家都喜欢。

这个时候,已经是2010年后了,移动互联网浪潮风起云涌,一只只猪在风口起飞了,又摔死了。老夫也已经踏出学校,开始在职场装逼了。

最贵铂金——HTTP2

HTTP2协议是建立在谷歌的SPDY上的。两者大体上其实差不多。比较大的变动就是:

  • 支持HTTP了,而SPDY是强制使用HTTPS的;
  • 更改了压缩算法;

这里要额外谈及的一点是,服务器推送。其实在SPDY的时候,服务器推送就支持了。比如说当你请求index.css的时候,服务器会把index.js一并推送过来,然后等浏览器真的请求index.js的时候,直接从本地缓存里面就可以得到。可以理解为买一送一了。

HTTP2->HTTP3

永恒钻石——QUIC?HTTP3?

要说游戏玩得好不好,最重要的是什么?意识!

现在HTTP协议发展到HTTP2之后,段位要想进一步提升,就得靠意识提升了。那么HTTP协议的意识是指什么?就是TCP协议了。现在的HTTP2协议,虽然还有很多的坑,但是制约性能的最关键因素,就是底层所依赖的TCP协议了。

回顾一下,历代HTTP版本为了应付低效TCP协议所做的努力:

  1. HTTP1.1的长连接;
  2. HTTP2的多路复用;

其实缓存之类的改进,也有部分原因是因为TCP的低效。如果将眼光再放宽一点,那么就会发现TCP已经算是计算机行业里面一个突出瓶颈了。

所以在HTTP3里面,就想要解决这个问题。但是这个问题其实很棘手。换成UDP肯定不行,因为UDP是不可靠的,不保证顺序的,没有拥塞控制和流量控制——虽然这些乱七八糟的东西都可以在应用层上解决,但是总不能在HTTP协议上解决一遍这个问题,在别的应用层面上再解决一遍。

所以,实际上,我们需要需要的是一个更加好的传输层协议。在这个时候,谷歌又搞了一个QUIC的东西。这个东西就是传说中将用于HTTP3的传输层协议。

QUIC连接建立

我们仔细思考一下TCP协议。其实TCP为人诟病的点,最主要的就是TCP连接建立太太太太慢了。所以QUIC第一个要解决的就是TCP连接慢的问题。如果是建立一个TCP+TLS连接,那就更加慢了。然而,不幸的是,HTTPS将会成为未来的主流,HTTP协议会慢慢退出舞台。

TCP三次握手才能建立连接;
TLS完全握手至少需要两个RTT,即便是简化握手也需要一个RTT;

QUIC就要简单粗暴很多了,一个RTT就能够完成连接建立。基本上就是客户端发起连接,服务端响应连接,然后所有的连接信息都交换完成,即便是使用了加密传输。

QUIC的搞法有点黑科技。它使用了新的加密算法Diffie–Hellman。这个算法细节就不讨论了,它的核心就是双方保留各自的私钥,而交换公钥、基底G和大质数P。然后就能计算出相等的私钥S,这个私钥就是用来加密数据的对称密钥。

更加可怕的是,如果客户端缓存了服务端交换的信息,那么下次就不再需要交换了,在0RTT上就可以建立连接。

队头阻塞

在SPDY里面,引入了多路复用。但是这个会带来一个很严重的问题——当然这个问题也是由TCP协议自身的特点带来的。这个问题就是如果TCP中间的某个数据包出现错误了,那么就会阻塞别的请求的数据包,这根源于TCP的滑动窗口协议——也就是要保证顺序。

而QUIC是基于UDP的,先天就没有这个问题。

QUIC其它

QUIC还有很多的特点,比如说,QUIC是利用UDP,那么就带来了一些问题:怎么做拥塞控制?怎么做差错恢复(如丢包怎么恢复)?反正就是,TCP有的而UPD没有的,QUIC要怎么支持。毕竟HTTP协议需要的是一个可靠的连接。

先埋个坑,有空补上QUIC的科普文章

总结

HTTP总体上来说,在现在的环境下,还看不到有什么协议能够取而代之。而大部分的改进都有一种修修补补的感觉。除了QUIC的改进,无论是多路复用,还是什么长连接,我都不太喜欢,感觉这个东西破坏了HTTP协议设计的简单和优雅。

HTTP的使用场景还在进一步扩大。最典型的就是谷歌的gRpc,就是依赖于HTTP2协议的。Spring boot本质上也就是HTTP协议的。将来,为了兼容各种异构的系统,基于文本的HTTP协议,依旧会是第一选择。

我感觉,QUIC或者HTTP3占据主流的时候,我觉得我的孩子估计都可以打酱油了。

相关文章

网友评论

      本文标题:那些年,我们一起追的HTTP协议……

      本文链接:https://www.haomeiwen.com/subject/zensrqtx.html