HTTP前世今生

HTTP/0.9 The One Liner

第一个版本的HTTP规范是1991年提出的HTTP/0.9。只支持GET方法。

举个例子:

Request

GET /index.html

Response

(response body)

(connection closed)

文字性再描述一遍

  1. Client(User Agent)发出一个Request
  2. Server返回一个html文档作为response后关掉链接

简单到令人发指的行为,所以

  • 没有headers
  • 只允许GET
  • Response必须是HTML

HTTP/1.0 – 发布于1996

1.0新增了不少方法,比如POST和HEAD等。Response的范围也放宽了不少,比如图像、视频、纯文本等。

Request和Response有了header,404等status code首次被加入进来。其他的,诸如字符集、认证、缓存等等常见的内容也是在1.0被添加进来的。

Request HTTP/1.0

GET / HTTP/1.0

Host: kamranahmed.info

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10105)

Accept: */*

Response HTTP/1.0

HTTP/1.0 200 OK 

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



(response body)

(connection closed)

值得注意的是,header是用ASCII编码的。但是,response的body已经可以是任意格式。

1.0最大的缺点是不支持TCP重用,每一个HTTP request都需要新建立一个TCP连接,这简直无法忍受。

在此期间,部分先驱者试图自定义一个headerConnection: keep-alive,可以没有被广泛的支持。

HTTP/1.1 发布于1999

1.1新增改动

  • 新的Request Method,PUT/PATCH/HEAD/OPTIONS/DELETE。

  • Request的Host header被指定为必须的。

  • Connection: keep-alive被写进规范,如果想要关掉这个连接,需要添加Connection: close到request header中。

  • Pipelining,支持用同一条TCP连接串行发送多个request,并等待response。在此情况下,response必须在header中添加Content-Length。

    有个问题,如果response没有固定的长度怎么办。为了解决这个问题,参考下面的Chunked Encoding。

  • Chunked Transfer,当server不知道整个response有多长的时候,可以用Chunked Transfer,也就是分片传输。每一小片发送的时候指定长度就可以了。当传输完成的时候,server发送一个空的chunk来标识结束。当然,为了和普通的response区分,发送chunk的时候要在response的header中添加Transfer-Encoding: chunked。

  • 1.0只支持基础认证,1.1支持digest和proxy认证。

  • 语言协商。

  • cookies。

  • 等等。

如果想知道所有1.0和1.1之间的区别,可以去查看RFC或者看看[Key differences between HTTP/1.0 and HTTP/1.1](http://www.ra.ethz.ch/cdstore/www8/data/2136/pdf/pd1.pdf)

SPDY 发布于2009 Google这个棒槌。。。

Google在2009年发布了SPDY。一个致力于提升Web网速和安全性的协议。

并且:

SPDY是Google的商标,不是首字母缩写……

其核心思想:

网络性能的提升可以由带宽提升来改进,但这么做是有瓶颈。之所以有瓶颈是因为网络传输附带着额外的、隐形的开销。如果能忽略这些额外的开销,网络性能的提升和带宽的提升就是线性关系。

对于那些不了解情况的人,额外的开销就是延迟。比如说,数据从源头发送到目的地需要花费多长时间。带宽就是每秒钟能传输多少数据量。

提供的功能:

  • 多路传输
  • 数据压缩
  • 传输优先级
  • 安全
  • 等等

SPDY的设计理念是作为一个HTTP之下的传输层协议。在request发送出去之前修改其内容。

到2015年的时候,google觉得多搞一层协议太麻烦了,所以就把SPDY的内容合并到HTTP协议,也就是HTTP/2。

HTTP/2 – 2015

HTTP/2设计用于降低传输内容时的额外开销。

几个关键不同点如下:

  • 二进制代替文本
  • 多路传输
  • HPACK压缩header
  • Server Push,一个request可以有多个response
  • Request优先级
  • 安全
  1. 二进制协议

    HTTP/2致力于用二进制内容代替HTTP/1.x中的文本内容。二进制的内容比文本内容更容易被计算机解析,但是难以阅读。

    HTTP/2最大的贡献就是帧和流。(Frames and Streams)

    Frames and Strems

    HTTP消息现在是由一个或多个frame组成。一个是由元数据(meta data)组成的header frame;一个由负载(payload)组成的数据frame;还有一些替他种类的frame,例如HEADERS、DATA、RST_STREAM、SETTINGS、PRIORITY等。参考链接HTTP/2规范

    每一个HTTP/2的request和response都有一个唯一的stream ID,并且被分割到各种类型的帧中。frame只是一小片数据的意思。一组frame的集合被称为Stream。每个帧由stream id来标示其属于哪个stream,并且同一个stream中的frame拥有相同的header。除了stream id是唯一的之外,还有一点需要注意,由client初始化的request用奇数作为stream id,而server发出的response用偶数作为stream id。

    除了HEADER和DATA frame,另一种比较值得注意的是RST_STREAM frame。这是一种特殊的用途frame,其用来中止stream。在HTTP/1.1中,如果想让server停止发送response,只能是断开当前的TCP链接。但这样做会导致额外的隐形开销,因为后续的request需要重新建立一条新的TCP链接。

  2. 多路传输

    HTTP/2是一个二进制协议并且使用frame和stream来传递request和response。一旦TCP链接建立成功,所有的stream都在这一条相同的链接上异步的收发。server回复response的时候也是无序的,client需要自己去根据stream id来重新组装报文。这正好解决了HTTP/1.x中的head-of-line阻塞问题。Client可以同时处理多个request而不用等待耗时长的那个。

  3. HPACK Header压缩

    这是RFC文档中被分离出来的一小部分。其解决的问题是,我们经常会在header中使用相同的内容,尤其是cookie部分。这导致了我们的网络请求使用很多额外的带宽。

    ![HPACK](http://i.imgur.com/3IPWXvR.png HPACK)

    和request body以及response body不一样的地方是,headers不会被gzip或者compress压缩。

    压缩Header采用一套完全不同的机制。HPACK使用哈弗曼编码和一个header表来维护client和server提供的headers。一句话,重复的header可以胜率。

    需要额外注意的是,一些附件的假header比如:method、:scheme、:host和:path等不在HPACK范围之内。

  4. Server Push(Server 推送)

    Server push是另外一个HTTP/2引进的令人惊奇的功能。当server了解到client将要请求某个资源的时候,server可以推送这个资源给client,即使client还没有发出对这个资源的请求。举个例子,当一个浏览器加载一个网页的时候,浏览器会解析整个页面来找出需要从server加载的远端内容,然后再去发送请求去获取资源。

    Server push允许server通过主动推送资源来减少上述的资源请求。当server push完成的时候,server发送一个特殊的PUSH_PROMISE frame来提醒client,“资源马上会发给你,不要发送请求”。PUSH_PROMISE frame与server推送资源的frame属于同一个stream。

  5. Request Prioritization 请求优先级

    Client在发送header frame的时候,可以在其中添加优先级。或者通过发送一个PRIORITY frame来改变stream的优先级。

    HTTP/2是用一条TCP连接完成多个request和response的,这从先天上导致了HTTP/2无法并行处理多个frame以及steam,所以如果没有这个优先级的设定,会导致某些高优先级的请求得不到即时处理。

    当不设定优先级的时候,server异步、无序处理request。如果steam有被设定优先级,server会基于优先级信息来决定使用多少资源来处理这个request。

  6. 安全

    曾经有一个非常广泛的讨论,关于是否要在HTTP/2中强制启用TLS。最后的结果是,不强制使用TLS。不管怎样,大多数厂商声明只支持启用了TLS的HTTP/2。因此,尽管HTTP/2规范不强制加密,但是有可能被默认启用加密。另外,HTTP/2使用基于TLS的加密规范时有一些附加的要求,例如,必须使用TLS v1.2或更高版本,以及最小密钥长度等等。

参考链接: Journey to HTTP/2

1 评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注