从Nginx配置缓存到HTTP缓存

使用nginx配置缓存

proxy_cache_path是nginx配置缓存的关键词,它是1.7.9之后的版本推出的功能。配置它很简单,只需要在nginx.conf里的http段里添加一句话:

1
proxy_cache_path /data/httpd/nginx_cache/ecstore levels=1:2 keys_zone=ecstore:100m max_size=2g inactive=168h;

上面的命令先说明/data/httpd/nginx_cache/ecstore就是nginx配置缓存的文件夹,keys_zone指的是缓存空间名称,100m意思是可以存储8000*100个key;max_size指的是缓存文件可以占用的最大空间;nactive指的是如果一个缓存文件多长时间不被访问,就会被删除;

然后手动建立/data/httpd/nginx_cache/ecstore这个文件夹,给予它nginx可访问的权限,然后在具体的配置文件里加上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    location = /wap/ {
if ($query_string) {
proxy_pass http://172.16.0.199:3000/wap/?$query_string;
}
proxy_pass http://172.16.0.199:3000/wap/;
include headerproxy.conf;
proxy_cache ecstore; #这里的ecstore就是上面keys_zone的名称
proxy_cache_key "$host$request_uri$cookie_user"; #这里就是缓存的key
proxy_cache_min_uses 5; #至少访问5次就开始缓存,默认情况是访问一次就缓存
proxy_cache_methods GET HEAD POST; #对GET、HEAD、POST方法都可以缓存
add_header X-Cache web1$upstream_cache_status;
proxy_cache_valid 200 206 302 301 304 2h; #对200、206、302、301、304状态码缓存2小时
proxy_no_cache $http_pragma $http_authorization;
}

上面这个例子就是“如果访问/wap,会跳转到http://172.16.0.199:3000/,同时记录下缓存” 的配置。重启nginx就会生效。

验证和排错

验证nginx是否缓存成功很简单,因为我们在配置文件夹加上了add_header X-Cache web1$upstream_cache_status;这样的配置,那么我们打开目标的网页:
akb48

发现看到了add_header的内容,可见缓存是成功的。

如果此刻给这个nginx外面套上一个CDN,那么curl -I在访问页面里具体元素的结果就会是:
akb48

我这里用的是阿里云的CDN,可见他们使用Server: Tengine做的CDN,而且这个js元素被CDN成功缓存。如果是TCP_MEM_HIT的字样,那么就说明是是从内存命中的。不同厂家的CDN展示结果不一样的。

如果nginx缓存没有生效,很大可能是Cache-ControlSet-Cookie的问题,那么就要在上面的配置文件里添加:

1
proxy_ignore_headers Set-Cookie Cache-Control;

重启nginx看看效果。

Vary跟Etag的差别

在上面的截图里看到了EtagVary这两个字段,先说Etag

Etag是一个比较常见的字段,HTTP利用它来判断所访问的元素是否发生了变化—如果浏览器发送请求的请求头If-None-Match里的Etag没有变化(为False)那么服务器就直接304,把缓存内容返给浏览器;如果Etag发生变化了,那么服务器就拿出新的内容给它同时反馈200。它比Last-Modified强的最重要的地方就是Last-Modified只能精确到秒,遇到1s内修改了N次的情况就只能干瞪眼了,而Etag不会。

而说Vary之前要先说一下Cache-ControlCache-Control有四个比较出名的缓存策略,分别是:
1.no-cache:可以在本地缓存,可以在代理服务器缓存,但是这个缓存要服务器验证才可以使用;
2.no-store:彻底得禁用缓存,本地和代理服务器都不缓存,每次都从服务器获取;
3.private:为仅浏览器客户端可缓存;
4.public:为多个用户都可以缓存,比如可以缓存到CDN上。

而图片里的Vary: Accept-Encoding是什么意思呢?它是告诉缓存服务器根据Accept-Encoding头值的不同去缓存不同的版本,比如同一个文件可能有gzip方式压缩的,有compress方式压缩的,甚至还有没压缩的。因为在实际的场景中,我们需要一些特殊的缓存:它会忽略响应头中的Content-Encoding,从而可能给不支持压缩的客户端返回缓存的压缩版本。有两个方案可以避免这种情况发生:
1.将响应头中的Cache-Control字段设为private,告诉中继缓存(比如CDN)不要缓存它;
2.增加Vary: Accept-Encoding响应头,明确告知缓存服务器按照Accept-Encoding字段的内容,分别缓存不同的版本;

通常为了更好的利用中间实体的缓存功能,我们都用第二种方案。对于cssjs这样的静态资源,只要客户端支持gzip,服务端应该总是启用它;同时为了避免有BUG的缓存服务器给用户返回错误的版本,还应该输出Vary: Accept-Encoding

nginx配置Vary:Accept-Encoding也很简单,在nginx.conf的http段里加上gzip_vary on;即可。

当然Vary还要很多种,比如Vary: User-Agent, Cookie,这表示“服务端同时使用请求头中User-Agent和Cookie这两个字段来生成内容”。注意!客户端如果直接访问源服务器的话,Vary就没意义了。

参考资料

https://blog.csdn.net/dengjiexian123/article/details/53386586
https://blog.csdn.net/t12x3456/article/details/17301897
https://www.jianshu.com/p/625c2b15dad5
https://imququ.com/post/vary-header-in-http.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
https://segmentfault.com/a/1190000016648967
akb48

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------