从HTTP到WEB缓存

8,855 阅读21分钟

一、HTTP 概述

HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。

HTTP是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础,是一种 client-server 协议,也就是说,请求通常是由像浏览器这样的接受方发起的。

客户端和服务端通过交换各自的消息(与数据流正好相反)进行交互。由像浏览器这样的客户端发出的消息叫做 requests,被服务端响应的消息叫做 responses。

1. 基本性质

  • HTTP是无连接的: 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 一个连接是由传输层来控制的,这从根本上不属于HTTP的范围。HTTP并不需要其底层的传输层协议是面向连接的,只需要它是可靠的,或不丢失消息的(至少返回错误)。
  • HTTP是可扩展的: 在 HTTP/1.0 中出现的 HTTP headers 让协议扩展变得非常容易。只要服务端和客户端就新 headers 达成语义一致,新功能就可以被轻松加入进来。
  • HTTP是无状态: HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。 使用Cookies可以创建有状态的会话。

2. HTTP 消息结构

1. 请求报文

HTTP请求报文由:请求行、请求头部、空行和请求数据四个部分组成。

2. 响应报文

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

二、HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法:GET, POST , HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE , CONNECT 方法。

方法 描述
GET 请求获取Request-URI所标识的资源。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除 Request-URI 所标识的资源。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器,主要使用SSL和TLS将数据加密后通过网络隧道进行传输。
OPTIONS 使服务器传回该资源所支持的所有HTTP请求方法。用 * 来代替资源名称,向 Web 服务器发送 OPTIONS 请求,可以测试服务器功能是否正常运作。
TRACE 回显服务器收到的请求,主要用于测试或诊断。

其中,最常见的是 GET 和 POST 方法,如果是 RESful 接口的话一般会用到 PUT、DELETE、GET、POST(分别对应增删查改)

三、HTTP 首部

主要分为通用首部、请求首部、响应首部和实体首部四种:

  • 通用首部字段:既可以出现在请求报文中,也可以出现在响应报文中,它提供了与报文相关的最基本的信息;
  • 请求首部字段:从客户端向服务器发送请求报文时使用的首部字段,补充了请求的附加内容,客户端信息,响应内容相关优先级等信息;
  • 响应首部字段:从服务器向客户端返回响应报文时使用的首部字段;补充了响应的附加内容,也会要求客户端附加额外的内容信息;
  • 实体首部字段:针对请求报文和响应报文的实体部分使用的首部,补充了资源内容的更新时间等与实体有关的信息。
  • 其他报文字段:这些字段不是HTTP协议中定义的,但被广泛应用于HTTP请求中。

1. 通用首部字段

首部字段名 说明
Cache-Control 控制缓存行为。
Connection 管理持久连接,设置其值为Keep-Alive可实现长连接。
Date 创建HTTP报文的日期和时间。
Pragma Http/1.1之前的历史遗留字段,仅作为HTTP/1.0向后兼容而定义,虽然是通用字段,当通常被使用在客户单的请求中,如Pragma: no-cache, 表示客户端在请求过程中不循序服务端返回缓存的数据。
Trailer 报文尾部的首部。
Transfer-Encoding 规定了传输报文主题时使用的传输编码,如Transfer-Encoding: chunked。
Upgrade 用于检查HTTP协议或其他协议是否有可使用的更高版本。
Via 追踪客户端和服务端之间的报文的传输路径,还可避免会环的发生,所以在经过代理时必须添加此字段。
Warning Http/1.1的报文字段,从Http/1.0的AfterRetry演变而来,用来告知用户一些与缓存相关的警告信息。

2. 请求首部字段

首部字段名 说明
Accept 客户端能够处理的媒体类型
Accept-Charset 表示客户端支持的字符集。例如:Accept-Charset: GB2312, ISO-8859-1
Accept-Encoding 表示客户端支持的内容编码格式。如:Accept-Encoding:gzip
Accept-Language 表示客户端支持的语言。如:Accept-Language: zh-cn, en
Authorization 表示客户端的认证信息。客户端在访问需要认证的也是时,服务器会返回401,随后客户端将认证信息加在Authorization字段中发送到服务器后,如果认证成功,则返回200
Host 表示访问资源所在的主机名,即URL中的域名部分。如:m.baidu.com
If-Match If-Match的值与所请求资源的ETag值(实体标记,与资源相关联。资源变化,实体标记跟着变化)一致时,服务器才处理此请求
If-Modified-Since 用于确认客户端拥有的本地资源的时效性
If-None-Match If-Match的值与所请求资源的ETag值不一致时服务器才处理此请求
If-Range If-Range的值(ETag值或时间)与所访问资源的ETag值或时间相一致时,服务器处理此请求,并返回Range字段中设置的指定范围的数据。如果不一致,则返回所有内容。If-Range其实算是If-Match的升级版,因为它的值不匹配时,依然能够返回数据,而If-Match不匹配时,请求不会被处理,需要数据时需再次进行请求
If-Unmodified-Since 与If-Modified-Since相反,表示请求的资源在指定的时间之后未发生变化时,才处理请求,否则返回412
Max-Forwards 表示请求可经过的服务器的最大数目,请求每被转发一次,Max-Forwards减1,当Max-Forwards为0时,所在的服务器将不再转发,而是直接做出应答。通过此字段可定位通信问题
Proxy-Authorization 当客户端接收到来自代理服务器的认证质询时,客户端会将认证信息添加到Proxy-Authorization来完成认证。与Authorization类似,只不过Authorization是发生在客户端与服务端之间
Range 获取部分资源,例如:Range: bytes=500-1000表示获取指定资源的第500到1000字节之间的内容,如果服务器能够正确处理,则返回206作为应答,表示返回了部分数据,如果不能处理这种范围请求,则以200作为应答,返回完整的数据
Referer 告知服务器请求是从哪个页面发起的
User-Agent 将发起请求的浏览器和代理名称等信息发送给服务端
Cookie 在请求时添加Cookie, 以实现HTTP的状态记录

3. 响应首部字段

首部字段名 说明
Accept-Ranges 是否接受字节范围。
Age 服务端告知客户端,源服务器(而不是缓存服务器)在多久之前创建了响应,单位为秒。
ETag 实体资源的标识,可用来请求指定的资源。
Location 请求的资源所在的新位置。
Proxy-Authenticate 将代理服务器需要的认证信息发送给客户端。
Retry-After 服务端告知客户端多久之后再重试,一般与503和3xx重定向类型的应答一起使用。
Server 告知服务端当前使用的HTTP服务器应用程序的相关信息。
Vary 代理服务器缓存的管理信息。
WWW-Authenticate 告知客户端适用于所访问资源的认证方案,如Basic或Digest。401的响应中肯定带有WWW-Authenticate字段。
Set-Cookie 服务器通过此字段给客户端传递Cookie信息。

4. 实体首部字段

首部字段名 说明
Allow 通知客户端,服务器所支持的请求方法。
Content-Encoding 告知客户端,服务器对资源的内容编码。
Content-Language 告知客户端,资源所使用的自然语言。
Content-Length 告知客户端资源的长度
Content-Location 告知客户端资源所在的位置。
Content-Type 告知客户端资源的媒体类型,取值同请求首部字段中的Accept。
Expires 告知客户端资源的失效日期。可用于对缓存的处理。
Last-Modified 告知客户端资源最后一次修改的时间。

5. 其他报文字段

X-Frame-Options:首部字段X-Frame-Options属于HTTP响应首部 用于控制网站内容在其他Web网站的Frame标签内的显示问题,主要目的是为了防止点击劫持攻击

X-XSS-Protection:首部字段X-XSS-Protection属于HTTP响应首部 针对跨站脚本攻击的一种对策,用于控制浏览器XSS防护机制的开关

DNT(Do Not Track):拒绝个人信息被收集,表示拒绝被精准广告追踪的一种方法

四、HTTP 状态返回码

状态码负责表示客户端请求的返回结果、标记服务器端是否正常、通知出现的错误。

状态码 类别 分类描述
1XX Informational(信息性状态码) 请求正在被处理
2XX Success(成功状态码) 请求处理成功
3XX Redirection(重定向状态码) 需要进行重定向
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态吗) 服务器处理请求时出错

1. 信息响应

状态码 短句 含义
100 Continue 继续,客户端应继续其请求
101 Switching Protocols 切换协议,只能切换到更高级的协议

2. 成功响应

状态码 短句 含义
200 OK 请求成功,一般用于GET与POST请求
201 Created 已创建,成功请求并创建了新的资源
202 Accepted 已接受,已经接受请求,但未处理完成

3. 重定向

状态码 短句 含义
300 Multiple Choices 多种选择,请求的资源可包括多个位置
301 Moved Permanently 永久移动
302 Found 临时移动,GET 或者 HEAD 请求
303 See Other 查看其它地址,与302类似。需使用GET请求查看
304 Not Modified 未修改,服务器返回此状态码时,不会返回任何资源
307 Temporary Redirect 临时重定向,不该改变请求方法

4. 客户端错误

状态码 短句 含义
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)
405 Method Not Allowed 客户端请求中的方法被禁止

5. 服务器错误

状态码 短句 含义
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 从远程服务器接收到了一个无效的响应
503 Service Unavailable 服务器暂时的无法处理客户端的请求
504 Gateway Time-out 未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

五、HTTP 内容类型

Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。

常见的媒体类型: 文本文件:text/html, text/plain, text/css, application/xml 图片文件:iamge/jpeg, image/gif, image/png; 视频文件:video/mpeg 应用程序使用的二进制文件:application/octet-stream, application/zip

常用的内容编码: gzip: 由文件压缩程序gzip生成的编码格式; compress: 由Unix文件压缩程序compress生成的编码格式; deflate: 组合使用zlib和deflate压缩算法生成的编码格式; identity:默认的编码格式,不执行压缩。

六、HTTP Cookie

Cookie主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie曾一度用于客户端数据的存储,因当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。由于服务器指定Cookie后,浏览器的每次请求都会携带Cookie数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器API已经允许开发者直接将数据存储到本地,如使用 Web storage API (本地存储和会话存储)或 IndexedDB 。


Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

(1) 会话期Cookie 浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。

(2) 持久性Cookie 和关闭浏览器便失效的会话期Cookie不同,持久性Cookie可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

(3) Secure 和 HttpOnly

  • 标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。

  • 为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。

(4) Cookie的作用域 Domain 和 Path 标识定义了Cookie的作用域:即Cookie应该发送给哪些URL。

七、HTTP/1.x的连接管理

连接管理是一个 HTTP 的关键话题:打开和保持连接在很大程度上影响着网站和 Web 应用程序的性能。在 HTTP/1.x 里有多种模型:短连接, 长连接, 和 HTTP 流水线

短连接 HTTP 最早期的模型,也是 HTTP/1.0 的默认模型,是短连接。每一个 HTTP 请求都由它自己独立的连接完成;这意味着发起每一个 HTTP 请求之前都会有一次 TCP 握手,而且是连续不断的。

长连接 一个长连接会保持一段时间,重复用于发送一系列请求,节省了新建 TCP 连接握手的时间,还可以利用 TCP 的性能增强能力。当然这个连接也不会一直保留着:连接在空闲一段时间后会被关闭(服务器可以使用 Keep-Alive 协议头来指定一个最小的连接保持时间)。

HTTP 流水线 HTTP 流水线在现代浏览器中并不是默认被启用的 HTTP/2 流水线已经被更好的算法给代替,如 multiplexing


域名分片

除非你有紧急而迫切的需求,不要使用这一过时的技术,升级到 HTTP/2 就好了。在 HTTP/2 里,做域名分片就没必要了:HTTP/2 的连接可以很好的处理并发的无优先级的请求。域名分片甚至会影响性能。大多数 HTTP/2 的实现还会使用一种称作连接凝聚的技术去尝试合并被分片的域名。

如果服务器端想要更快速的响应网站或应用程序的应答,它可以迫使客户端建立更多的连接。

浏览器有并发限制,是为了防止Dos/DDoS攻击。

例如,不要在同一个域名下获取所有资源,假设有个域名是www.example.com我们可以把它拆分成好几个域名:www1.example.com、www2.example.com 所有这些域名都指向同一台服务器,浏览器会同时为每个域名建立多条连接。

这一技术被称作域名分片(域名发散)

域名收敛 就是将静态资源放在一个域名下,减少DNS解析的开销。


八、 HTTP 缓存

重用已获取的资源能够有效的提升网站与应用的性能。Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。

1. 各种类型的缓存

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。

  • 缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用,私有缓存只能用于单独用户。

下文将主要介绍浏览器缓存,除此之外还有代理缓存、网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上,为站点和 web 应用提供更好的稳定性、性能和扩展性。

常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。

2. 缓存规则

为了方便理解,我们认为浏览器存在一个缓存数据库,用于存储缓存信息(实际上静态资源是被缓存到了内存和磁盘中),在浏览器第一次请求数据时,此时缓存数据库没有对应的缓存数据,则需要请求服务器,服务器会将缓存规则和数据返回,浏览器将缓存规则和数据存储进缓存数据库。

我们可以将其分为两大类强缓存协商缓存

2.1 强缓存

浏览器如果判断本地缓存未过期,就直接使用,无需发起http请求(200 from memory/disk cache)

HTTP 1.0

服务器使用的响应头字段为 Expires ,值为未来的绝对时间(时间戳),浏览器请求时的当前时间超过了 Expires 设置的时间,代表缓存失效,需要再次向服务器发送请求,否则都会直接从缓存数据库中获取数据。


HTTP 1.1

Cache-Control 是最重要的规则,默认为private。

private     私有缓存
public      共享缓存
max-age     缓存的内容将在 xxx 秒后失效
no-cache    需要使用对比缓存来验证缓存数据
no-store    所有内容都不会缓存,强缓存、协商缓存都不会触发

注意:在 HTTP 1.0 版本中,Expires 字段的绝对时间是从服务器获取的,由于请求需要时间,所以浏览器的请求时间与服务器接收到请求所获取的时间是存在误差的,这也导致了缓存命中的误差,在 HTTP 1.1 版本中,因为 Cache-Control 的值 max-age=xxx 中的 xxx 是以秒为单位的相对时间,所以在浏览器接收到资源后开始倒计时,规避了 HTTP 1.0 中缓存命中存在误差的缺点,为了兼容低版本 HTTP 协议,正常开发中两种响应头会同时使用,HTTP 1.1 版本的实现优先级高于 HTTP 1.0


2.2 协商缓存

浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

HTTP 1.0

  • If-Modified-Since/Last-Modified 这两个是成对出现的,属于协商缓存的内容,其中浏览器的头部是If-Modified-Since,而服务端的是Last-Modified,它的作用是,在发起请求时,如果If-Modified-Since和Last-Modified匹配,那么代表服务器资源并未改变,因此服务端不会返回资源实体,而是只返回头部,通知浏览器可以使用本地缓存。Last-Modified,顾名思义,指的是文件最后的修改时间,而且只能精确到1s以内

HTTP 1.1

  • If-None-Match/E-tag 这两个是成对出现的,属于协商缓存的内容,其中浏览器的头部是If-None-Match,而服务端的是E-tag,同样,发出请求后,如果If-None-Match和E-tag匹配,则代表内容未变,通知浏览器使用本地缓存,和Last-Modified不同,E-tag更精确,它是类似于指纹一样的东西,基于FileEtag INode Mtime Size生成,只要文件变,指纹就会变,而且没有1s精确度的限制



为了使缓存策略更加健壮、灵活,HTTP 1.0 版本 和 HTTP 1.1 版本的缓存策略会同时使用,甚至强制缓存和协商缓存也会同时使用,对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接使用缓存,超出有效时间,执行协商缓存策略,对于协商缓存,将缓存信息中的 Etag 和 Last-Modified 通过请求头 If-None-Match 和 If-Modified-Since 发送给服务器,由服务器校验同时设置新的强制缓存,校验通过并返回 304 状态码时,浏览器直接使用缓存,如果协商缓存也未命中,则服务器重新设置协商缓存的标识。

3. 带Vary头的响应

Vary HTTP 响应头决定了对于后续的请求头,如何判断是请求一个新的资源还是使用缓存的文件。

当缓存服务器收到一个请求,只有当前的请求和原始(缓存)的请求头跟缓存的响应头里的Vary都匹配,才能使用缓存的响应。

使用vary头有利于内容服务的动态多样性。例如,使用Vary: User-Agent头,缓存服务器需要通过UA判断是否使用缓存的页面。如果需要区分移动端和桌面端的展示内容,利用这种方式就能避免在不同的终端展示错误的布局。另外,它可以帮助 Google 或者其他搜索引擎更好地发现页面的移动版本,并且告诉搜索引擎没有引入Cloaking。


参考文章: