HTTP 1.1学习笔记

版权声明:本文由史燕飞原创文章,转载请注明出处: 
文章原文连接:https://www.qcloud.com/community/article/111html

来源:腾云阁 https://www.qcloud.com/community数据库

 

因为HTTP 1自身的局限性,它不能很好的为用户提供性能良好的WEB服务。于1999年6月正式发布了HTTP1.1标准REC2616,它厘清了以前版本中不少有歧义的地方,并且还新增了不少重要的优化,如持久链接、分块编码传输、状态码扩充、加强的缓存机制、传输编码及请求管道等。本文是我的在学习《WEB性能权威指南》后,又查阅了一些文档资料写的一篇随笔,仅供参考和我的之后查阅。下面将对比http1.0讲述一些在新版本中的重要改进。浏览器

1.持久链接

每一个TCP链接在创建初期都须要进行三次握手,须要经历一次客户端与服务器间的完整往返,若是进行数据传输的话,至少还须要引起另一次往返。再加上服务器端的处理请求的时间,就是能够获得每次请求的总时间。若是每次发送请求都是由新建的TCP链接发送的话,它至少须要两次完整的网络往返时间,由于每一个TCP链接的创建都须要从新进行三次握手。缓存

那么,能不能对TCP链接进行重用呢?安全

答案无疑是确定的,HTTP1.1里添加了持久链接的支持,再次发送请求时,能够直接使用上次已经创建完成的TCP链接,这样就避免了第二次TCP链接时的三次握手、消除另外一次TCP慢启动的往返,极大了减少了网络延时。若是重用CTP链接发送HTTP请求的次数越多,带来的性能提高越可观,由于在第一次通过三次握手创建链接以后,无需再花费多余的时间再创建链接。性能优化

注:目前,全部现代浏览器都尝试持久化HTTP链接,若是服务器支持的话。使用HTTP1.1的话,默认的就是持久链接;若是使用HTTP 1.0,能够明确使用connection:keep-alive首部声明使用持久链接;还应注意一些HTTP库和框架的默认行为,它们有时候并非默认使用持久链接的。服务器

2.HTTP管道

持久HTTP可让咱们重用已有的链接来完成屡次请求,但这些请求须要知足先进先出的队列顺序:发送请求--等待响应,再发送下一个请求。HTTP/1.1容许多个http请求经过一个套接字同时被输出 ,而不用等待相应的响应。而后请求者就会等待各自的响应,这些响应是按照以前请求的顺序依次到达。(全部请求保持一个FIFO的队列,一个请求发送完以后,没必要等待这个请求的响应被接受到,下一个请求就能够被再次发出;同时,服务器端返回这些请求的响应时也是按照FIFO的顺序)。cookie

在高延迟和多请求的场景下,经过HTTP管道进行数据传输会有更大的性能提高,会节省更多的时间。通过仔细的观察,能够发如今HTTP1.1中存在一些局限,它严格串行的返回响应,它不容许多个数据交错到达(多路复用),只能等待一个响应彻底返回后,下一个响应才能发送,不管下一个响应是否早于前一个响应完成处理,这也叫作队首阻塞。这就带来一个很是糟糕的体验,若是第一个请求须要处理的时间很是长,那么后续的请求即便被服务器已经处理完成,响应也不能当即返回,而是存储在服务端的缓存区中,等待第一个响应的完成,才能按照FIFO顺序返回。网络

因为TCP严格按照按顺序交付,丢失一个TCP分组就会阻塞全部高序号的分组,除非重传丢失的分组,这也会带来额外的延迟。因为HTTP1.1中不容许多路复用,HTTP管道也会带来一些不容忽视的问题:并发

  • 一个慢响应会阻塞全部后续请求;

  • 并行处理请求时,服务器须要缓存处理结果,会占用服务器资源,若是某个响应很大,很容易造成服务器的受攻击面;

  • 响应失败可能终止TCP链接,会强迫客户端从新发送对后续资源的请求,致使重复处理;

  • 网络环境中存在中间代理,检测管道兼容性十分必要;

  • 若是中间代理不支持管道,那它可能中断链接,也可能把全部请求串联起来。

正是因为存在这样或那样的问题,HTTP管道技术的应用比较有限,并无大面积推广开来,即便一些支持它的浏览器也仅仅把它做为一个高级选项。若是你对客户端和服务端都有很强的控制力,依然可使用它,会带来不错的性能提高。若是要在采用这种技术,你须要注意如下事项:

  • 确保HTTP客户端支持管道;

  • 确保HTTP服务器支持管道;

  • 应用必须处理中断的链接并恢复;

  • 应用必须处理中断的请求的幂等问题;

  • 应用必须保持自身不受出问题的代理的影响。

实践中部署HTTP管道的最佳途径,就是在客户端和服务端使用HTTPS,这样就能够免除不支持管道的中间代理的干扰。

3.加强的缓存机制

在HTTP/1.0中,使用Expire头域来判断资源的fresh或stale,并使用条件请求(conditional request)来判断资源是否仍有效。
相关字段:

  • Date: 服务器响应的时间;

  • Expires: 资源过时时间;

  • Last-Modified: 资源最后修改时间;

  • If-Modified-Since: 用来验证资源是否过时;

大体策略为:

若是Expires设置的时间在Date以后,则浏览器在Expires标记的时间以前都不会访问服务器了,而是使用浏览器缓存;若是Expires设置的时间在Date以前,或者浏览器时间已经在Expires以后,那么再次访问资源时, 浏览器就要向服务器发送请求,但不是从新拉取数据,而是询问服务器该资源是否过时,方法时,把上次response中Last-Modified的时间做为If-Modified-Since的时间,发送请求,服务器对比该时间和资源目前的更改时间,若是未更改,则返回304,不然传输新文件。此外,HTTP/1.0中还定义了Pragma:no-cache头域,客户端使用该头域说明请求资源不能从cache中获取,而必须回源获取。

HTTP/1.0中,If-Modified-Since头域使用的是绝对时间戳,精确到秒,但使用绝对时间会带来不一样机器上的时钟同步问题,文档的 更新周期小于1s, 都会出现问题。

为了提供更好的缓存机制,HTTP1.1对以往的机制进行了一个渐进性的改进。HTTP/1.1提倡的缓存机制是,对比文档的hash值,文档内容变,则hash变,用相对时间代替绝对时间,这样就能够解决使用绝对时间戳带来一些问题。

HTTP/1.1 继承 HTTP/1.0 因此HTTP/1.0的相关字段仍然有效,保留的这些字段就是为了兼容那些仅支持HTTP/1.0的客户端。 HTTP/1.1服务器不该该设置与1.0矛盾的过时策略, 1.1的服务器在没有文档hash值时,也可使用If-Modified-Since进行判断文档过时。
HTTP1.1中新增了如下字段:

  • Cache-Control: 用来控制浏览器的缓存行为;

  • ETag: 文档的Hash值;

  • If-None-Match: 用来验证资源是否过时,即文档Hash值是否变化。

而HTTP/1.1中引入了一个ETag头域用于重激活机制,它的值ETag能够用来惟一的描述一个资源。请求消息中可使用If-None-Match头域来匹配资源的entitytag是否有变化。

为了使caching机制更加灵活,HTTP/1.1增长了Cache-Control头域(请求消息和响应消息均可使用),它支持一个可扩展的指令子集:例如max-age指令支持相对时间戳;private和no-store指令禁止对象被缓存;no-transform阻止Proxy进行任何改变响应的行为;no-cache浏览器缓存,可是认为是过时缓存;no-store浏览器不缓存;max-age:缓存有效时间段等等。

若是想要浏览器每次发送请求,还启用缓存,那就使用Cache-Control: no-cache, 每次访问图片,浏览器都会去验证Etag。

Cache使用关键字索引在磁盘中缓存的对象,在HTTP/1.0中使用资源的URL做为关键字。但可能存在不一样的资源基于同一个URL的状况,要区别它们还须要客户端提供更多的信息,如Accept-Language和Accept-Charset头域。为了支持这种内容协商机制(content negotiation mechanism),HTTP/1.1在响应消息中引入了Vary头域,该头域列出了请求消息中须要包含哪些头域用于内容协商。

4.分块编码传输

HTTP消息中能够包含任意长度的实体,一般它们使用Content-Length来给出消息结束标志。可是,对于不少动态产生的响应,只能经过缓冲完整的消息来判断消息的大小,但这样作会加大延迟。若是不使用长链接,还能够经过链接关闭的信号来断定一个消息的结束。

HTTP/1.1中引入了Chunke dtransfer-coding来解决上面这个问题,发送方将消息分割成若干个任意大小的数据块,每一个数据块在发送时都会附上块的长度,最后用一个零长度的块做为消息结束的标志。这种方法容许发送方只缓冲消息的一个片断,避免缓冲整个消息带来的过载。

在HTTP/1.0中,有一个Content-MD5的头域,要计算这个头域须要发送方缓冲完整个消息后才能进行。而HTTP/1.1中,采用chunked分块传递的消息在最后一个块(零长度)结束以后会再传递一个拖尾(trailer),它包含一个或多个头域,这些头域是发送方在传递完全部块以后再计算出值的。发送方会在消息中包含一个Trailer头域告诉接收方这个拖尾的存在。

5.状态码扩充

状态码是试图理解和知足请求的三位数字的整数码。HTTP/1.0中只定义了16个状态响应码,对错误或警告的提示不够具体。HTTP/1.1引入了一个Warning头域,增长对错误或警告信息的描述。

截止到HTTP1.1中包含的状态码大体以下:

状态代码 状态信息 含义

消息(1**)

100 Continue 初始的请求已经接受,客户应当继续发送请求的其他部分。(HTTP 1.1新)
101 Switching Protocols 服务器将听从客户的请求转换到另一种协议(HTTP 1.1新)

成功(2**)

200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经建立了文档,Location头给出了它的URL。
202 Accepted 已经接受请求,但处理还没有完成。
203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,由于使用的是文档的拷贝(HTTP 1.1新)。
204 No Content 没有新文档,浏览器应该继续显示原来的文档。若是用户按期地刷新页面,而Servlet能够肯定用户文档足够新,这个状态代码是颇有用的。
205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容(HTTP 1.1新)。
206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。

重定向(3**)

300 Multiple Choices 客户请求的文档能够在多个位置找到,这些位置已经在返回的文档内列出。若是服务器要提出优先选择,则应该在Location应答头指明。
301 Moved Permanently 客户请求的文档在其余地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。
302 Found 相似于301,但新的URL应该被视为临时性的替代,而不是永久性的。注意,在HTTP1.0中对应的状态信息是“Moved Temporatily”。
出现该状态代码时,浏览器可以自动访问新的URL,所以它是一个颇有用的状态代码。

注意这个状态代码有时候能够和301替换使用。例如,若是浏览器错误地请求 http://host/~user(缺乏了后面的斜杠), 有的服务器返回301,有的则返回302。

严格地说,咱们只能假定只有当原来的请求是GET时浏览器才会自动重定向。请参见307。
303 See Other 相似于301/302,不一样之处在于,若是原来的请求是POST,Location头指定的重定向目标文档应该经过GET提取(HTTP 1.1新)。
304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(通常是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还能够继续使用。
305 Use Proxy 客户请求的文档应该经过Location头所指明的代理服务器提取(HTTP 1.1新)。
307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即便原来的请求是POST,即便它实际上只能在POST请求的应答是303时 才能重定向。因为这个缘由,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器能够跟随重定向的GET和POST请求;若是是307应答,则浏览器只能跟随对GET请求的重定向。(HTTP 1.1新)

请求错误(4**)

400 Bad Request 请求出现语法错误。
401 Unauthorized 客户试图未经受权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,而后在填写合适的Authorization头后再次发出请求。
403 Forbidden 资源不可用。服务器理解客户的请求,但拒绝处理它。一般因为服务器上文件或目录的权限设置致使。
404 Not Found 没法找到指定位置的资源。这也是一个经常使用的应答。
405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。(HTTP 1.1新)
406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容(HTTP 1.1新)。
407 Proxy Authentication Required 相似于401,表示客户必须先通过代理服务器的受权。(HTTP 1.1新)
408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户能够在之后重复同一请求。(HTTP 1.1新)
409 Conflict 一般和PUT请求有关。因为请求和资源的当前状态相冲突,所以请求不能成功。(HTTP 1.1新)
410 Gone 所请求的文档已经再也不可用,并且服务器不知道应该重定向到哪个地址。它和404的不一样在于,返回407表示文档永久地离开了指定的位置,而404表示因为未知的缘由文档不可用。(HTTP 1.1新)
411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。(HTTP 1.1新)
412 Precondition Failed 请求头中指定的一些前提条件失败(HTTP 1.1新)。
413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。若是服务器认为本身可以稍后再处理该请求,则应该提供一个Retry-After头(HTTP 1.1新)。
414 Request URI Too Long URI太长(HTTP 1.1新)。
416 Requested Range Not Satisfiable 服务器不能知足客户在请求中指定的Range头。(HTTP 1.1新)

服务器错误(5**)

500 Internal Server Error 服务器遇到了意料不到的状况,不能完成客户的请求。
501 Not Implemented 服务器不支持实现请求所须要的功能。例如,客户发出了一个服务器不支持的PUT请求。
502 Bad Gateway 服务器做为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答。
503 Service Unavailable 服务器因为维护或者负载太重未能应答。例如,Servlet可能在数据库链接池已满的状况下返回503。服务器返回503时能够提供一个Retry-After头。
504 Gateway Timeout 由做为代理或网关的服务器使用,表示不能及时地从远程服务器得到应答。(HTTP 1.1新)
505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本。(HTTP 1.1新)

6.Host头域

在HTTP1.0中认为每台服务器都绑定一个惟一的IP地址,所以,请求消息中的URL并无传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上能够存在多个虚拟主机(Multi-homed Web Servers),而且它们共享一个IP地址。因为HTTP 1.0不支持Host请求头字段,WEB浏览器没法使用主机头名来明确表示要访问服务器上的哪一个WEB站点,这样就没法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增长Host请求头字段后,WEB浏览器可使用主机头名来明确表示要访问服务器上的哪一个WEB站点,这才实现了在一台WEB服务器上能够在同一个IP地址和端口号上使用不一样的主机名来建立多个虚拟WEB站点。

7.请求方式新增

客户程序向服务器发送的请求能够有不一样的类型,这样服务器能够根据不一样的请求类型进行不一样的处理。在HTTP1.0中,定义了三种最基本的请求类 型,GET、POST和HEAD,当使用GET和POST方法时,服务器最后都将结果文档返回给客户程序,浏览器将刷新显示;而HEAD请求则不一样,HEAD请求在客户程序和服务器之间进行交流,而不会返回具体的文档,它仅仅交流一些内部数据,这些数据不会影响浏览的过程。所以HEAD方法一般不单独使用,而是和其余的请求方法一块儿起到辅助做用。一些搜寻引擎使用的自动搜索机器人使用这个方法来得到网页的标志信息,或者进行安全认证时,使用这个方法来传递认证信息。

除了上述三种最多见的访问方法以外,在HTTP1.1中还定义了更多的访问方法类型,具体以下:

  • PUT:向指定资源位置上传其最新内容;

  • DELETE:请求服务器删除Request-URI所标识的资源;

  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也能够利用向Web服务器发送'*'的请求来测试服务器的功能性;

  • TRACE:回显服务器收到的请求,主要用于测试或诊断;

  • CONTENT:HTTP/1.1协议中预留给可以将链接改成管道方式的代理服务器。

这些方法并不经常使用,于是大部分Web服务器软件并无实现他们。然而对于特定场合他们仍是很是有用的,若是服务器不支持客户发送的请求方法,服务器将返回错误并当即关闭链接。

8.带宽优化

HTTP/1.0中,存在一些浪费带宽的现象,例如客户端只是须要某个对象的一部分,而服务器却将整个对象送过来了,又好比下载大文件时须要支持断点续传功能,而不是在发生断连后不得不从新下载完整的包。HTTP/1.1中在请求消息中引入了range头域,它容许只请求资源的某个部分。在响应消息中Content-Range头域声明了返回的这部分对象的偏移值和长度。若是服务器相应地返回了对象所请求范围的内容,则响应码为206(Partial Content),它能够防止Cache将响应误觉得是完整的一个对象。

另一种状况是请求消息中若是包含比较大的实体内容,但不肯定服务器是否可以接收该请求(如是否有权限),此时若贸然发出带实体的请求,若是被拒绝也会浪费带宽。HTTP/1.1加入了一个新的状态码100(Continue)。客户端事先发送一个只带头域的请求,若是服务器由于权限拒绝了请求,就回送响应码401(Unauthorized);若是服务器接收此请求就回送响应码100,客户端就能够继续发送带实体的完整请求了。注意,HTTP/1.0的客户端不支持100响应码。但可让客户端在请求消息中加入Expect头域,并将它的值设置为100-continue。

节省带宽资源的一个很是有效的作法就是压缩要传送的数据。Content-Encoding是对消息进行端到端(end-to-end)的编码,它多是资源在服务器上保存的固有格式(如jpeg图片格式);在请求消息中加入Accept-Encoding头域,它能够告诉服务器客户端可以解码的编码方式。而Transfer-Encoding是逐段式(hop-by-hop)的编码,如Chunked编码。在请求消息中加入TE头域用来告诉服务器可以接收的transfer-coding方式。

9.性能优化

9.1使用多个TCP链接

上文已经说明,HTTP1.X并不支持多路复用,请求须要在客户端排队等待发送,并且容易遇到队首阻塞的问题,并不能很好的提升数据传输速率。那么,既然不能对单一链接进行多路复用,那是否是能够同时打开多个链接进行数据传输呢?答案是确定的,浏览器开发商为了解决这个问题,使浏览器支持客户端最多打开六个链接,这样咱们就能够更快速的进行通讯。任何事情都两面性,同时打开多个链接势必带来一些优化和问题,具体以下:
优势:

  • 客户端能够并行发起多个请求;

  • 服务器能够并行处理多个请求;

  • 第一次往返能够发送的累计分组数量是原来的6倍;

缺点:

  • 更多的套接字会占用更多的资源;

  • 并行TCP流之间竞争共享的带宽;

  • 处理多个套接字,实现更为复杂;

  • 即便并行TCP流,应用的并发能力也受限制。

这种打开多个链接的方式,也带来了一些坏处,那为何如今还使用的如此普遍呢?主要由如下三个缘由:

  • 做为绕过HTTP限制的一个权宜之计;

  • 做为绕过TCP中低起始拥塞窗口的一个权宜之计;

  • 做为客户端绕过不能使用TCP窗口缩放的一个权益之计。

9.2域名分区

因为HTTP1.1协议不支持多路复用,迫使浏览器开发商为了提升通讯效率,引入并维护着链接池,每一个主机能够有6个TCP流。根据HTTP Archive统计,目前平均每一个页面要包含90个左右的资源,若是这些资源都来自于同一个主机,即便能够同时打开6个TCP流,依然会致使明显的排队情形。咱们并不须要把全部的资源都放在同一个主机上,能够分开放置到不一样的域名下,这样就能够增长能够同时打开的TCP流总数,能够突破浏览器的链接限制,实现更高的并发能力。

理论上来讲,使用的域名越多,并行能力也就越强。可是,在发送请求以前都须要进行DNS解析,不一样的域名须要分别进行解析,都须要进行额外的DNS查询,若是域名数量过多,会致使大量的额外解析;在TCP链接中存在的慢启动机制,有时候也会下降性能;并且每多一个套接字都须要客户端和服务端消耗资源进行维护;更糟糕的是,开发者须要手动的把这些资源进行分区,部署到不一样的域名下。域名分区的数量太大或过小都会影响性能,但如何肯定最优的分区数量并是个很好回答的问题,由于页面中资源的数量、客户端链接的可用带宽及延迟等都会影响分区数量的合理性。

要想肯定合适的域名分区数量,只能用最原始的方式从最小分区开始不断的测试,观察不一样分区数目对应用的影响,而后选择最优的一个值做为固定分区数目。

9.3链接与合并

最快的请求就是不用请求,无论什么协议或什么类型的应用,减小请求次数老是最好的优化手段。若是每一个资源都是必不可少的,那你能够考虑把这些资源打包到一块,经过一次网络请求获取。链接和拼合技术属于之内容为中心的应用层优化,经过减小网络往返开销,能够明显的提高性能。但是这些技术也须要额外的处理、部署和编码,也会带来额外的复杂性。把多个资源打包到一块儿,也可能给缓存带来负担,一些细微的更新都须要从新请求资源并缓存,有时候当前页面并不须要文件中的其余一些资源,这都会影响页面的执行速度。

在采用链接与合并技术时,虽然会减小网络往返开销和提高性能,但也会增长应用的复杂度,以至缓存、更新、执行速度、渲染页面等问题。因此,采用这种优化时,应综合考虑,寻求一种最佳的文件打包粒度。

9.4嵌入资源

嵌入资源也是一种很常见的优化方法,把资源嵌入文档能够减小请求的次数。嵌入页面的资源适合特别小的,使用次数不多,最好是一次的资源。实践中,一个经验规则是只考虑嵌入1-2KB如下的资源,由于小于这个标准的资源会致使比它自身更高的HTTP开销。然而,若是嵌入资源频繁变动,也会致使宿主文档的无效缓存率升高。若是应用中要使用很小的、个别的文件,在考虑是否嵌入时,能够参考如下建议:

  • 若是文件很小,并且只有个别页面使用,能够考虑嵌入;

  • 若是文件很小,但须要在多个页面中使用,应该考虑集中打包;

  • 若是文件常常须要更新,就不要嵌入了;

  • 经过减小HTTP cookie的大小将协议开销最小化。

参考资料:
《WEB性能权威指南》
《HTTP/1.1与HTTP/1.0的区别》
《HTTP 1.1与HTTP 1.0的比较》
http://www.faqs.org/rfcs/rfc1945.html
http://www.faqs.org/rfcs/rfc2616.html

相关文章
相关标签/搜索