6

如何控制浏览器缓存

 2 years ago
source link: https://zzyongx.github.io/blogs/brower_200_from_disk_cache_vs_304.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何控制浏览器缓存

WEB开发缓存优化第一原则:缓存离用户越近,性能越高。无疑,浏览器是离用户最近的。那么如何控制浏览器缓存呢? 我以前错误的以为,如果没有显式告知浏览器缓存,那么浏览器就不会缓存,这引起了很大问题。

1 Last-Modified

如果没有指定 ExpiresCache-Control 但是指定了 Last-Modified ,浏览器会猜应该缓存多久。对多数浏览器而言,缓存的时长是 (现在时间 - Last-Modified时间)* 10% 。越老的文件缓存的时间越长。这种控制缓存的方式相当任性,最好显式指定缓存。

2 Cache-Control 和 Expires

可以通过 Cache-ControlExpires 显式的指定缓存。 Cache-Control 的优先级高于 ExpiresCache-Control 指定相对时间,而 Expires 指定绝对时间。例如:

  1. Cache-Control: max-age=0 不缓存
  2. Expires: 0 不缓存
  3. Cache-Control: max-age=60 缓存60S
  4. Expires: Mon, 27 Feb 2017 05:08:53 GMT 在GMT时间2017-2-27 05:08:53过期

除了过期时间,*Cache-Control* 还有其它选项,Cache-Control参考

3 200 (from disk cache)、(from memory cache)

在chrome开发者工具中会看到 Status 200 Size (from disk cache) Size (from memory cache) ,这个的含义是:从浏览器缓存中读取数据,不会真的访问server端。性能最高。

如果缓存已经过期,会重新请求server端。如果缓存中有 ETag ,那么往server端发请求时会带着 If-None-Match ,值和 ETag 一致。如果缓存中有 Last-Modified ,那么往server端发请求时会带着 If-Modified-Since ,值和 Last-Modified 一致。 If-None-Match 优先级高于 If-Modified-Since ,如果服务端判定缓存仍然有效,返回304。虽然304对服务端有真实的请求,但是响应没有BODY,性能也很高。

对于静态资源,推荐的做法是使用版本或签名作为文件名,更改内容时更新版本和签名,这样可以在浏览器端设置很长的过期时间。但是对于html,文件名不应该改变,应该通过减少缓存时间,甚至不设置缓存。

6 nginx 配置

# cache-control for static resource
set $cache_control "";
if ($uri ~ "\.(?:html|json)$") {
  set $cache_control "public, max-age=0, must-revalidate";
}
if ($uri ~ "\.(?:jpg|jpeg|gif|png|ico|svg|mp4|ttf)$") {   # 100 days
  set $cache_control "public, max-age=8640000";
}
if ($uri ~ "\.(?:css|js)$") {   # 1 day
  set $cache_control "public, max-age=86400";
}
add_header Cache-Control $cache_control;

7 浏览器如何请求资源

浏览器请求资源的方式影响缓存的使用(浏览器间有不同),资源分主资源和子资源。直接在地址栏输入的是主资源,主资源自己请求的资源是子资源。看例子, api/test 设置了 Cache-Control: max-age=60,private ,但是没有设置 ETagLast-Modifiedtest.html 是静态页面,它包含了 api/test 子资源,另外 XHR 请求也属于子资源请求。

  1. http://dev/api/test
  2. http://dev/test.html 内容是
<script src="http://dev/api/test"></script>
<a href="http://dev/api/test">Test</a>

在浏览器的地址栏输入上面的两个地址:其中1没有使用缓存,虽然 api/test 设置了缓存,但是并没有使用(因为是主资源,所以总是发请求,且没有 ETagLast-Modified 所以没有返回304)。2包含了两个资源,再次刷新,test.html 返回304(因为它是主资源,所以总是请求服务端), api/test 使用缓存(在chrome中)。但是在firefox中 api/test 也没有使用缓存,只有点击Test打开连接时 api/test 才使用了缓存。

除了在地址栏输入地址,点击刷新按钮,摁F5,还可以通过 Ctl-F5 强制刷新,此时所有的缓存都被忽略(老版本的IE不支持)。

了解这些并没有太多用,但是如果你想测试接口的缓存效果,发现每次刷新都没有使用缓存,可能是浏览器请求资源方式的缘故。

8 Cache-Control 注意事项

8.1 max-age=0,no-cache,no-store 的区别

  • max-age=0 的意思是缓存,但是不使用它,当从服务端获取资源失败时,可以考虑使用。
  • no-cache 的意思是缓存,但是不使用它,仅当从服务端返回了304时,才使用。
  • no-store 的意思是不缓存。

8.2 private

private 对浏览器没有太多意义,更多的是针对CDN或充当CDN的nginx之类,它告诉CDN不要缓存此类响应。例如:同一个url,针对cookie中的用户不同,返回不同的内容,应该是private的,此时CDN就不应该缓存。

8.3 浏览器请求时带着:max-age=0

这是告诉CDN不要使用缓存的内容,把请求代理到upstream服务器。

9 浏览器之间的差异

各家浏览器基于自己对缓存和性能的理解,对缓存的处理不同,以上描述不是对所有浏览器都适用,但没有本质影响。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK