缓存这个概念不管是在前端还是后端都是息息相关,且需要前后端一起配合,本文以前端的视角做分析。
一道被问过多次的面试题:
浏览器请求跟缓存相关的概念有哪些?
cache-control,expires。。。
ETag知道吗?
没有(这是神马东西?)
以chrome抓取到的百度请求一个js文件为例:
200初次请求
-------------------------------
304刷新请求
-------------------------------
等回来经过大量查询,总结如下:
Cache-Control http1.1
max-age 资源在本地缓存多少秒(注意单位是秒)
no-cache 浏览器不会缓存文件,不管刷新,回车,回退都请求最新
privite 响应只能够作为私有的缓存(e.g., 在一个浏览器中),不能再用户间共享
public 响应会被缓存,并且在多用户间共享。正常情况, 如果要求HTTP认证,响应会自动设置为 private
Expires:
缓存过期时间,允许客户端在这个时间之前不去检查(发请求),属于http1.0,优先级比cache-control低,根据客户端的时间计算,如果客户端和服务器端时间不一致
就会有问题。所以在http1.1里有了cache-control的
概念,
last-modified: 服务器端文件最后修改时间,数值如果和request的if-Modified-Since相同则使用304缓存
ETag: 一个标记,当服务器端资源发送改变时,ETag也随之发生变化,数值如果和request的if-None-Match相同则使用304缓存。
If-Modified-Since: 客户端缓存文件的最后修改时间last-modified
if-none-match: 客户端缓存文件的etag值
cache-control: max-age=0
no-cache
Prama:no-cache HTTP 1.0中定义的, 所以为了兼容HTTP 1.0. 会同时使用Pragma: no-cache和Cache-Control: no-cache
使用ETag主要是为了解决Last-Modified 无法解决的一些问题。
1. 某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
2. 某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。
3. 一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
1. 刷新
2. 浏览器的回退按钮
3. 地址栏回车
4. 强制刷新(command+shift+r)
区别:
刷新会去请求服务器,如果返现if-none-match和if-modified-since 分别与服务器的etag和last-modified一致,则返回304,浏览器使用缓存,注意此过程是有请求的
浏览器回退和地址栏回车都是浏览器的行为,直接使用客户端的缓存,即200 from cache
强制刷新会重新请求,没有304
不过以上如果服务器端设置cache-control:none,则不管是哪种行为,都会重新请求 200 没有缓存
发现这个问题还是从requirejs说起,
图中的r.js就是requirejs,当刷新的时候发现requirejs加载的js文件一直是200 from cache,最初以为跟requirejs内部实现有关,查看源码发现并没有做缓存,每次都是重新
用新的script标签请求,然后就开始猜测难道跟动态加载有关系,那就试试jquery加载的
结果是jquery动态加载的刷新后也是200 from cache,那就来个自己动态加载,经过测试,也是如此,所以初步判断是动态加载的缓存后刷新默认使用浏览器的缓存,
因为并不是很确定,所以请教了公司的大牛,得到的答复为
“
刷新的时候,会忽略Expires/Cache-Control的设置,再次向服务器请求
而页面后续异步加载的资源不受影响,
所以还会from cache
”