输入url后处理过程小结

    2015年10月08日 doc test 字数:2523

从客户端发起一个HTTP请求到用户接收到响应之间,都发生了什么


在日常阅读以及面试过程中,都会看到这类问题。从客户端发起一个HTTP请求到用户接收到响应之间,都发生了什么。大概流程梳理下来,涉及的知识点很多也很基础,记录一下方便后续巩固。

整体流程

如下流程是从 http://stackoverflow.com/questions/2092527/what-happens-when-you-type-in-a-url-in-browser 翻译得来,具体可看原文。

  1. 浏览器检查cache,如果请求对象在cache中,则跳至第9步
  2. 浏览器向操作系统获取服务端的ip地址
  3. 操作系统通过DNS协议查找并将IP地址返回给浏览器
  4. 浏览器向服务端发起tcp连接(https会更复杂)
  5. 浏览器通过tcp连接发送http请求
  6. 浏览器接收到http响应体后,有可能会关闭tcp连接也有可能在下一个请求时继续使用
  7. 浏览器检查响应包体的状态码,是否是重定向,认证失败,响应失败超时等问题。根据不同的问题,进行不同的处理
  8. 如果是有cache able字段,这将请求保存在本地cache中
  9. 浏览器针对返回字段解析对应的包体
  10. 浏览器根据拿到的返回值进行渲染

大致流程如上所述,其中该流程涉及到了 dns协议、tcp协议、http协议、浏览器缓存等概念。接下来根据这几个概念逐一介绍。

tcp协议详解

http协议详解

http协议内容很多,暂且按照定义、特点、请求字段、响应字段四个基础点记录

一、http定义

HTTP协议用于定义客户端与web服务器通迅的格式。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议就是用于定义通迅格式的协议

二、http协议特点

  1. 支持客户/服务器模式。
  2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  3. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  4. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  5. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

三、http请求字段

一个http请求包含三部分:(参考http://hao.jser.com/archive/8331/此处理解)

  1. 请求行。指明请求类型和请求URI
  2. 请求头。
  3. 请求包体。即请求的字段及其值

四、http响应

在接收和解释请求消息后,服务器返回一个HTTP响应消息。 HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文

  1. 状态行 指的是2xx,3xx,4xx,5xx等状态码
  2. 消息报头
  3. 响应正文

五、消息报头

消息报头主要有普通报头,请求报头,响应报头,实体报头。

持久连接: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字段

Last-Modified首部是服务端对客户端的HTTP响应所加的一个与缓存有关的HTTP首部,该首部标记了所请求资源在服务端的最后修改时间。类似: Last-Modified : Fri , 12 May 2015 13:10:33 GMT 当客户端发现HTTP响应头中有Last-Modified,会对资源进行缓存,在下次请求资源时,在HTTP请求头中添加If-Modified-Since首部,首部中将会添加上次成功请求资源时响应头部的Last-Modified属性值,即: 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首部,如下:

ETag:W/”a627ff1c9e65d2dede2efe0dd25efb8c”

当客户端发现ETag头部时,同样会对资源进行缓存,并在下次请求时,在请求头部添加If-None-Match,如:

If-None-Match:W/”a627ff1c9e65d2dede2efe0dd25efb8c”

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

缓存时间:Expires 和 Cache-Control

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

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

Expires:Thu, 19 Nov 2015 15:00:00 GMT

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

但是,Expires有一个不足的地方是,如果服务端时间与客户端本地时间不统一时,可能服务端让客户端可以对该资源缓存一个小时,而客户端本地时间比服务端时间快了两个小时,那就意味着,所有缓存都将不会生效。

于是有了弥补该不足的一个属性,即:Cache-Control。如果服务端在响应首部添加该属性时,客户端将直接使用该属性值来生成本地时间的缓存过期时间,这样便解决了这个问题,如下:

Cache-Control:max-age=3600

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

浏览器缓存

这块主要是两块,首先明确浏览器取缓存内容的类型、其次是缓存机制的理解。

一、浏览器取缓存内容的类型

  1. 本地缓存: 直接从本地取页面缓存; 如果缓存的页面有expires(绝对时刻)或Cache-Control:max-age(时长),则在有效时间内,则取本地页面,不会给浏览器发请求。
  2. 协商缓存: 与web服务器协商,判断是否取浏览器缓存。 如果没有expires或max-age,则浏览器会发请求到服务器,附上If-Modified-Since报文头,web服务器则会判断页面是否在这个时间后有更新过,如没有则返回一个304状态,浏览器取本地缓存的内容;否则,服务器将返回200状态,并返回该资源和Last-Modified。

在浏览器(如IE)中有几种操作,如下:

  1. 强制刷新:Ctrl + F5 浏览器将绕过本地缓存、协商缓存,让服务器重新发送请求的资源。
  2. 刷新:F5 浏览器将绕过本地缓存,将使用协商缓存来请求资源。
  3. 转向或回车: 浏览器将使用本地缓存、协商缓存。

二、具体的浏览器缓存机制

  • http://www.laruence.com/2010/03/05/1332.html
  • http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html

参考这两篇即可