面向HTTP的Web性能提升方案

引言

  • 前端优化是个永恒的课题
  • 前端优化的方案非常多,诸如加快脚本加载速度、缓存优化、提升js执行效率、运用ajax技术等等;
  • 本文重点介绍面向HTTP的一些Web性能提升方案;

到底发生什么了?

  • 建立TCP连接
    • 为了进行可靠的数据传输,TCP在进行发送数据之前,会进行TCP三次握手,以此确定接收方能够成功收取传输的数据,而建立连接的过程,必然是要耗费系统资源,以及时间资源的。
  • 服务端处理并响应
    • 当服务端接收到客户端发送来的请求之后,如果请求内容是静态资源,服务端会从硬盘中取出静态资源,然后将静态资源放在响应主体中,发送给客户端。如果是动态资源,服务端首先取出资源,并通过业务逻辑操作,动态生成最终的响应主体,然后发送给客户端。
  • 客户端渲染
    • 客户端接受到服务端传输过来的网络资源,然后进行渲染,绘制等,最终展示给用户。

优化点一:持久连接Keep-Alive

  • HTTP连接设计之初是请求-响应-关闭,也就是每建立一次HTTP连接,只能进行一次资源请求,当需要在同一目标服务器上获取多个资源的时候,就需要多次建立HTTP连接,而这个多次建立连接的过程,便降低了网站的性能。
  • 于是,出现了Connection:Keep-Alive,人称持久连接。Keep-Alive避免了建立或者说重新建立连接的过程,减少了HTTP连接。
  • 而与此配套的有Keep-Alive:timeout=120,max=5
  • 其中,timeout=120 是指这个TCP通道保持120S,max=5 指这个TCP通道最多接收5个HTTP请求,之后便自动关闭该连接。

优化点二:修改时间Last-Modified 和 If-Modified-Since

  • Last-Modified首部是服务端对客户端的HTTP响应所加的一个与缓存有关的HTTP首部,该首部标记了所请求资源在服务端的最后修改时间。类似:
1
Last-Modified : Fri , 12 May 2015 13:10:33 GMT
  • 当客户端发现HTTP响应头中有Last-Modified,会对资源进行缓存,在下次请求资源时,在HTTP请求头中添加If-Modified-Since首部,首部中将会添加上次成功请求资源时响应头部的Last-Modified属性值,即:
1
If-Modified-Since : Fri , 12 May 2015 13:10:33 GMT
  • 当服务端接收到的HTTP请求中,发现有If-Modified-Since头部时,会将该属性值与请求资源的最后修改时间进行比对,如果最后修改时间与该属性值一致时,服务端会返回一个304 Not Modified响应,该响应中不包括响应实体。浏览器收到304的响应后,会进行重定向,获取本地缓存资源。如果最后修改时间与该属性值不一致,则会从服务端重新获取资源,做出200响应。

优化点三:版本标记 ETag 和 If-None-Match

  • ETag其实与Last-Modified是差不多的方式,但是ETag并没有选择以时间作为标记,而是对所请求文件进行某些算法来生成一串唯一的字符串,作为对某一文件的标记。当收到客户端对某一资源的请求时,服务端在响应时,添加ETag首部,如下:
1
ETag:W/"a627ff1c9e65d2dede2efe0dd25efb8c"
  • 当客户端发现ETag头部时,同样会对资源进行缓存,并在下次请求时,在请求头部添加If-None-Match,如:

    1
    If-None-Match:W/"a627ff1c9e65d2dede2efe0dd25efb8c"
  • 当服务端收到请求中含有该头部时,会使用同样的ETag生成算法对文件ETag进行计算,并与If-None-Match属性值进行比对,如果一致,则返回一个304 Not Modified响应,基本与上一种方式是一致的。

优化点四:缓存时间 Expires 和 Cache-Control

  • 上述两种方式中,每次请求资源时,虽然在有缓存的情况下,选择缓存进行渲染绘制,但是在这之前还是发起了一次HTTP请求,虽然并没有真实的响应实体,但是依然会造成一些资源消耗。而Expires与上述两种方式使用了不同的思路。

  • 当服务端希望客户端浏览器对某一资源进行缓存时,为了免去客户端每次都要询问自己:我上次的缓存现在还能用吗?所以,服务端选择了放权。只去告诉浏览器,我这次给你的资源你可以用多长时间,在这个时间段内,你可以一直使用它,无需每次咨询我。而服务端就是通过Expires属性来告诉客户端浏览器可以多长时间内不需要询问服务端。如下:

    1
    Expires:Thu, 19 Nov 2015 15:00:00 GMT
  • 当客户端在响应首部中发现该属性值时,便会将该资源缓存起来,而缓存的过期时间即是Expires中的时间。在这个时间段内,浏览器完全自主。

  • 但是,Expires有一个不足的地方是,如果服务端时间与客户端本地时间不统一时,可能服务端让客户端可以对该资源缓存一个小时,而客户端本地时间比服务端时间快了两个小时,那就意味着,所有缓存都将不会生效。
  • 于是有了弥补该不足的一个属性,即:Cache-Control。如果服务端在响应首部添加该属性时,客户端将直接使用该属性值来生成本地时间的缓存过期时间,这样便解决了这个问题,如下:

    1
    Cache-Control:max-age=3600
  • 如果客户端在2015年10月01日13时00分00秒收到该响应时,便会加上3600秒也就是2015年10月01日14时00分00秒作为缓存过期时间。如果响应头部既有Expires和Cache-Control,浏览器会首选Cache-Control。

您的支持是对我最大的鼓励!