访问一个网站,每次http请求都从通过网络服务器下载js/css/image等内容,不仅会导致页面加载时间变长,同时也增加了服务器的访问流量导致服务器压力增大。对于大型网站,通过http缓存可以快网站的响应速度,减小服务器的压力。
这都得益于每个浏览器都支持http缓存功能,只要在发送http请求时,设置相应的请求头即可(包括缓存时间)。
发起一次http请求,并观察header头信息:
- Request headers
GET /static/admin/images/nginx.jpg HTTP/1.1
Host: think5.1.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://think5.1.com/nginxExpire
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,und;q=0.7
- Response header
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Mon, 31 Aug 2020 02:14:00 GMT
Content-Type: image/jpeg
Content-Length: 16023
Last-Modified: Sat, 06 Jun 2020 13:17:32 GMT
Connection: keep-alive
ETag: "5edb976c-3e97"
Expires: Mon, 31 Aug 2020 02:14:10 GMT
Cache-Control: max-age=10
Accept-Ranges: bytes
在response header信息中跟缓存相关是Last-Modified(资源的最后修改时间)、ETag(f资源验证令牌,用于验证资源是否被修改)、Expires(缓存过期时间)、Cache-Control(指示客户端最多缓存10s)。
ETag验证缓存响应
如果在首次获取资源的10s内又发起了请求,浏览器会先检查缓存,如果缓存没有过期,则直接从缓存读取。
Request URL: http://think5.1.com/static/admin/images/nginx.jpg
Request Method: GET
Status Code: 200 OK (from memory cache)
Remote Address: 127.0.0.1:80
Referrer Policy: no-referrer-when-downgrade
如果缓存过期,浏览器会再次请求服务器,获取资源,但如果资源未发生变化,重新下载是没有必要的,ETag验证令牌就是为了解决这样的问题,浏览器只需要在发起请求时将上一次请求响应的Etag验证令牌通过请求头If-None-Match标签发送给服务端,
- request headers
GET /static/admin/images/nginx.jpg HTTP/1.1
Host: think5.1.com
Connection: keep-alive
If-Modified-Since: Sat, 06 Jun 2020 13:17:32 GMT
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
If-None-Match: "5edb976c-3e97"
Accep t: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://think5.1.com/nginxExpire
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,und;q=0.7
- Response headers
HTTP/1.1 304 Not Modified
Server: nginx/1.16.0
Date: Mon, 31 Aug 2020 05:38:27 GMT
Last-Modified: Sat, 06 Jun 2020 13:17:32 GMT
Connection: keep-alive
ETag: "5edb976c-3e97"
Expires: Mon, 31 Aug 2020 05:38:37 GMT
Cache-Control: max-age=10
在上面的请求中,客户端(浏览器)自动在“If-None-Match”请求标头内加上了ETag令牌,服务端会自行对比令牌,如果Etag令牌没有变化,服务器会响应304 Not Modified,告知浏览器资源未发生变化,将过期缓存延长10s。注意这里会直接跳过下载,节省了带宽。
Cache-Control
Cache-Control 标头是在HTTP/1.1规范中定义的,取代了之前的用来定义响应缓存策略的标头(如Expires)
http协议允许服务器在响应标头中返回Cache-Control 来控制浏览器或者其他中间缓存层如何缓存响应内容以及缓存多久。
- no-cache
从字面上看no-cache 是无缓存的意思,其实并不是这样的,它的真实含义是必须要与服务器确认返回的响应是否发生了变化。才能在后续请求中使用该响应,即在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)。 - no-store
no-store 缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。 - public
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。) - private
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。
比如用户的个人隐私页面不希望被cdn等中间缓存层缓存,那么可以通过private指令来指明,从而可以禁止cdn等中间缓存层对用户隐私页面的缓存。
- max-age=<seconds>
设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。
更多关于cache-control的缓存指令可参考:地址
通过以下流程可以指定最佳的缓存策略:
缓存更新与废弃
使用缓存必然是好的,如果我对某个css设置了3天的缓存,当更新了css的内容时候,客户端缓存并未到期,如何控制客户端缓存废弃与更新呢?
- 对于html通常可以采用如下设置,一下设置表示: 表示客户端可以缓存资源,每次使用缓存资源前都必须重新验证其有效性。这意味着每次都会发起 HTTP 请求,但当缓存内容仍有效时可以跳过 HTTP 响应体的下载。
Cache-Control: no-cache
Cache-Control: max-age=0
- 对于静态资源css/js/image 可通过设置版本号来控制客户端的缓存的废弃与更新。
例如:
http://think5.1.com/static/admin/images/nginx.jpg?v=202009061224123
http://think5.1.com/static/admin/js/hello.js?v=202009061224123
http://think5.1.com/static/admin/css/top.css?v=202009061224123