今晚走了很长时间的弯路,最后发现问题在于 url load 访问 和 Command+R 刷新上,道路曲折但是很有意思。
问题的起源在于晚上把一个demo部署到阿里云上,在配置nginx的时候,设置了expire。但是当用Chrome检查Network的时候,发现已经设置了expire的css,js,image 总是返回304(Not Modified)的状态。因为之前服务器缓存资源出现返回304的问题,所以就打算看下到底是什么问题
首先,我断定自己的expire是没有设置错的:
|
|
于是开始查看是否是ETag的配置问题?
- 弯路1:nginx自从1.3版本后默认带有etag,木有发现,然后去github下载第三方ETag插件编译。。。 1.3版本后可以通过设置 etag on|off实现 etag 的配置,并且默认开启etag.
Web服务器我们以nginx为例,以css文件为例,ETag可以理解为一个文件的标记,是唯一的.
ETag的工作原理是:
- 第一次访问, nginx会返回ETag值,浏览器会记录下来
Request
|
|
Response
|
|
- 第二次访问时,浏览器会带着上次nginx返回的ETag值作为If-None-Match的值,发起请求,这时候nginx会把If-None-Match值与该页面对应的ETag值进行比较,如果不相等则返回200,重新下载资源;如果二者相等,则返回304,浏览器调用本地缓存。
Request
|
|
Response
|
|
但是比较纳闷的是为什么本地有缓存了,设置expire也成功了,浏览器不直接读取cache内容而是先去web服务器请求了一次?
正常的 from cache 的 Request(应该说没有发起请求) 和 Response 应该是这样的:
Request
|
|
Response
|
|
后来看到知乎的一个问题 阿里云存储如何让浏览器始终以200 (from cache)缓存图片,里面有一句话:
通过大家的回答和我自己的实验发现(Chrome上),对于阿里云的云存储,加大Cache-Control的max-age是有效的,这点我之前也试过,但是像 @yuanyuanVivian说的,是在输入URL按下回车时有效,直接刷新时图片还是无法直接加载缓存,而且无法禁用阿里云存储Etag.
受到启发,终于找到问题所在了:
- 弯路2:URL回车或者链接访问URL 与 刷新或者强制刷新(mac下的Command+R,win下的F5,Ctrl+F5等)这两种方式浏览器的处理方式是不一样的:前者操作方式,浏览器获取资源的时候不会设置 Cache-Control:max-age=0,所以如果expire设置的max-age如果仍有效的话会优先从本地cache中获取;但是后者发起Request的时候浏览器给 header 里设置的 Cache-Control:max-age=0,可以参照上文第2次访问请求。我们都知道一旦max-age为0,则不会从本地cache获取数据了,所以会发起一次http请求,nginx根据header里传来的If-Modified-Since或者If-None-Match分别与Last-Modified,Etag做对比,从而做出返回304还是200的选择,而强制刷新是将 hreader 设置为 Cache-Control:no-cache,直接返回200,下载资源.
所以说 设置的 expire 是生效的。正常情况用户点链接的话,属于加载,不属于刷新,缓存的静态资源肯定会优先从本地cache获取,但是刷新的时候就避免不了一次http请求获取304了。
Expire 和 ETag 都有缓存的作用,但是区别在于:
Expire 第二次访问的时候会直接从 本地cache获取,即 200(From Cache),ETag会发起一次http请求,最后返回304(Not Modified)
分布的问题:因为Expire第二次访问不会发起http请求,所以不存在前后资源访问不在同一台机器上的问题;但是由于每台机器在某一个时刻针对某一个资源生成ETag的值不一样,将会导致如果第二次请求分配到了另外的机器,If-None-Match与另外的服务器ETag值不对应,则重新下载资源,导致本地缓存失效!
所以在有多台web服务器的情况下要优先使用Expire.
具体nginx对Expire和Etag使用优先级是什么?这个只能阅读源码,以后探索了
参考资料:
- Module ngx_http_core_module
- HTTP头信息中的参数Etag
- 200 OK (FROM CACHE) 与 304 NOT MODIFIED
- 阿里云存储如何让浏览器始终以200 (from cache)缓存图片?
- Best Practices for Speeding Up Your Web Site
- HTTP status code 200 (cache) vs status code 304?
- Reload vs. Refresh in Firefox (Cache-Control)