博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实操 Web Cache (第二版)
阅读量:6516 次
发布时间:2019-06-24

本文共 22055 字,大约阅读时间需要 73 分钟。

hot3.png

实操 Web Cache

http://netkiller.github.io/journal/cache.html

Mr. Neo Chen (陈景峰), netkiller, BG7NYT

中国广东省深圳市龙华新区民治街道溪山美地
518131
+86 13113668890
+86 755 29812080
<>

$Id

版权声明

转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。

27090958_Kzbh.png
文档出处:

2015-08-27

摘要

写这篇文章的原因,是我看到网上很多谈这类的文章,多是人云亦云,不求实事,误导读者。

下面文中我会一个一个做实验,并展示给你,说明为什么会这样。只有自己亲自尝试才能拿出有说服力的真凭实据。

2014-03-12 首次发布

2015-08-27 修改,增加特殊数据缓存

我的系列文档


目录

1. 测试环境

CentOS 6.5

Nginx安装脚本 https://github.com/oscm/shell/blob/master/nginx/nginx.sh

php安装脚本 https://github.com/oscm/shell/blob/master/php/5.5.8.sh

2. 文件修改日期 If-Modified-Since / Last-Modified

If-Modified-Since 小于 Last-Modified 返回 HTTP/1.1 200 OK, 否则返回 HTTP/1.0 304 Not Modified

每次浏览器请求文件会携带 If-Modified-Since 头,将当前时间发送给服务器,与服务器的Last-Modified时间对对比,如果大于Last-Modified时间,返回HTTP/1.0 304 Not Modified不会重新打开文件,否则重新读取文件并返回内容

2.1. 静态文件

nginx/1.0.15 静态文件自动产生 Last-Modified 头

# nginx -vnginx version: nginx/1.0.15# curl -I http://192.168.6.9/index.htmlHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 07:36:03 GMTContent-Type: text/htmlContent-Length: 6Last-Modified: Thu, 27 Feb 2014 07:29:50 GMTConnection: keep-aliveAccept-Ranges: bytes

图片文件

# curl -I http://192.168.6.9/image.pngHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 07:37:18 GMTContent-Type: image/pngContent-Length: 41516Last-Modified: Thu, 27 Feb 2014 07:36:59 GMTConnection: keep-aliveAccept-Ranges: bytes

提示

疑问 nginx/1.4.5 默认没有 Last-Modified

# nginx -vnginx version: nginx/1.4.5# curl -I http://192.168.2.15/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:13:44 GMTContent-Type: text/htmlConnection: keep-alive

经过一番周折最终找到答案 Nginx 如果开启 ssi 会禁用Last-Modified 关闭 ssi 后输出如下

# curl -I  http://localhost/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:44:29 GMTContent-Type: text/htmlContent-Length: 6Last-Modified: Wed, 25 Dec 2013 03:18:16 GMTConnection: keep-aliveETag: "52ba4e78-6"Accept-Ranges: bytes

再测试一次

# curl -H "If-Modified-Since: Fir, 28 Feb 2014 07:42:55 GMT" -I http://192.168.2.15/test.htmlHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:34:54 GMTLast-Modified: Fri, 28 Feb 2014 01:55:50 GMTConnection: keep-aliveETag: "530feca6-8b"

测试结果成功返回 HTTP/1.1 304 Not Modified, 但又莫名其妙的出现了 ETag。 这就是Nignx本版差异,非常混乱。

既然出现了ETag我们也顺便测试一下

# curl -H 'If-None-Match: "530feca6-8b"' -I http://192.168.2.15/test.htmlHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:39:18 GMTLast-Modified: Fri, 28 Feb 2014 01:55:50 GMTConnection: keep-aliveETag: "530feca6-8b"

也是成功的

测试图片

# curl -I http://localhost/logo.jpgHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:59:04 GMTContent-Type: image/jpegContent-Length: 10103Last-Modified: Fri, 28 Feb 2014 02:56:37 GMTConnection: keep-aliveETag: "530ffae5-2777"Accept-Ranges: bytes# curl -H 'If-None-Match: "530ffae5-2777"' -I http://localhost/logo.jpgHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 03:03:33 GMTLast-Modified: Fri, 28 Feb 2014 02:56:37 GMTConnection: keep-aliveETag: "530ffae5-2777"# curl -H "If-Modified-Since: Fri, 28 Feb 2014 12:04:18 GMT" -I http://localhost/logo.jpgHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 03:04:45 GMTContent-Type: image/jpegContent-Length: 10103Last-Modified: Fri, 28 Feb 2014 02:56:37 GMTConnection: keep-aliveETag: "530ffae5-2777"Accept-Ranges: bytes

测试结果,ETag通过测试,If-Modified-Since无论如何也无法返回 304 可能还需要其他的HTTP头,浏览器测试都通过返回 HTTP/1.1 304 Not Modified

现在换成浏览器测试 Chrome Firefox成功, 因为浏览器不会主动发送If-Modified-Since, 浏览器只有发现Last-Modified后,第二次请求才会推送 If-Modified-Since 需要刷新两次页面。

2.1.1. if_modified_since

在开启ssi的情况下,通过参数 if_modified_since 可以开启 Last-Modified

server {    listen       80;    server_name  192.168.2.15;    if_modified_since before;}

测试结果看不到 Last-Modified, 因为 Nginx 的 if_modified_since before;参数只有接收到浏览器发过来的If-Modified-Since头才会发送Last-Modified

# curl -I http://192.168.2.15/test.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:39:42 GMTContent-Type: text/htmlConnection: keep-alive

最终 if_modified_since before; 数没有起到作用

参数设置为 if_modified_since exact;

# curl -I http://192.168.2.15/test.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:45:40 GMTContent-Type: text/htmlConnection: keep-alive# curl -H 'If-None-Match: "530feca6-8b"' -I http://192.168.2.15/test.htmlHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:45:44 GMTLast-Modified: Fri, 28 Feb 2014 01:55:50 GMTConnection: keep-aliveETag: "530feca6-8b"# curl -H "If-Modified-Since: Fir, 28 Feb 2014 07:42:55 GMT" -I http://192.168.2.15/test.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 02:45:50 GMTContent-Type: text/htmlConnection: keep-alive

测试失败,浏览器也是实测失败,ETag却成功

2.2. 通过rewrite伪静态处理

index.php仍然是上面的那个php文件,我们只是做了伪静态

location / {        root   /www;        index  index.html index.htm;		rewrite ^/test.html$ /index.php last;}

现在我们分别通过curl有chrome/firefox进行测试

# curl -H "If-Modified-Since: Fri, 28 Feb 2014 08:42:55 GMT" -I  http://192.168.6.9/test.htmlHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 08:55:19 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Thu, 26 Feb 2014 08:39:35 GMT

经过测试无论是 curl 还是 chrome/firefox 均无法返回304.

下面是我的分析,仅供参考。用户请求index.html Nginx 会找到该文件读取 mtime 与 If-Modified-Since 匹配,如果If-Modified-Since大于 Last-Modified返回 304否则返回200.

为什么同样操作经过伪静态的test.html就不行呢? 我分析当用户请求test.html Nginx 首先做Rewrite处理,然后跳转到index.php 整个过程nginx 并没有访问实际物理文件test.html也就没有mtime, 所以Nginx 返回200.

如果 Nginx 按预想的返回304,nginx 需要读取程序返回的HTTP头,Nginx 并没有这样的处理逻辑。

2.3. 动态文件

动态文件没有 Last-Modified 头,我们可以伪造一个

# curl -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 07:57:59 GMTContent-Type: text/htmlConnection: keep-alive

在程序中加入HTTP头推送操作,Last-Modified时间是27号,当前时间是28号,我们要让Last-Modified 小于当前时间才行。

# cat index.php
Hello

现在你将看到 Last-Modified

# curl -I http://localhost/modified.phpHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:59:28 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 10:04:18 GMT

注意

虽然我们让动态程序返回了 Last-Modified ,但浏览器不认,经过测试 Chrome / Firefox 均不会承认.php文件,并缓存其内容。

# curl -I http://localhost/modified.phpHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:59:28 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 10:04:18 GMT# curl -H "If-Modified-Since: Fri, 28 Feb 2014 08:42:55 GMT" -I  http://localhost/modified.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Fri, 28 Feb 2014 05:32:30 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Thu, 26 Feb 2014 08:39:35 GMT

Last-Modified 对动态程序来说没有起到实际作用

Last-Modified是程序产生的,Nginx无法读到,让程序去处理状态返回是可行的,下面我们修改程序如下。

# cat modified.php
= $mtime) { header('Last-Modified: '.$mtime, true, 304); exit; } else { header('Last-Modified: ' . $mtime ); }}print_r($_SERVER);echo date("Y-m-d H:i:s");?>

测试效果

# curl -I http://localhost/modified.phpHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:22:28 GMTContent-Type: text/htmlConnection: keep-alive

伪造一个 If-Modified-Since 日期小于我们指定的日期程序返回HTTP/1.1 200 OK

# curl -H "If-Modified-Since: Fri, 28 Feb 2014 10:04:18 GMT" -I http://localhost/modified.phpHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:22:13 GMTContent-Type: text/htmlConnection: keep-alive

伪造一个 If-Modified-Since 日期大于我们指定的日期程序返回HTTP/1.1 304 Not Modified

# curl -H "If-Modified-Since: Fri, 28 Feb 2014 20:04:18 GMT" -I http://localhost/modified.phpHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 05:21:31 GMTConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 12:04:18 GMT

测试成功,并且在浏览器端也测试成功 HTTP/1.1 304 Not Modified

将modified.php伪静态处理

location / {        root   /www;        index  index.html index.htm;		rewrite ^/modified.html$ /modified.php last;    }

测试

# curl -I http://localhost/modified.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 06:21:10 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 10:04:18 GMT# curl -H "If-Modified-Since: Fri, 28 Feb 2014 12:04:18 GMT" -I http://localhost/modified.htmlHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 06:21:22 GMTConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 10:04:18 GMT

达到预期效果

3. ETag / If-None-Match

上面的Last-Modified测试中发现ETag虽然不限制,但是暗中还是可用的:)

etag on; 开启Nginx etag支持,lighttpd 默认开启

server {    listen       80;    server_name phalcon;    charset utf-8;    access_log  /var/log/nginx/host.access.log  main;	etag on;    location / {        root   /www/phalcon/public;        index  index.html index.php;    }}

检查ETag输出

# curl -I http://localhost/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 03:08:28 GMTContent-Type: text/htmlConnection: keep-alive# curl -I http://phalcon/img/css.pngHTTP/1.1 200 OKServer: nginxDate: Thu, 27 Feb 2014 09:20:49 GMTContent-Type: image/pngContent-Length: 1133Last-Modified: Fri, 14 Feb 2014 08:05:03 GMTConnection: keep-aliveETag: "52fdce2f-46d"Accept-Ranges: bytes3

即使你开启了 ETag Nginx 对 HTML、CSS文件也不做处理。最终在一个外国网站是找到一个nginx-static-etags模块,有兴趣自己尝试,这里就不讲了。

3.1. 静态文件

首先查询etag值

# curl -I http://phalcon/img/css.pngHTTP/1.1 200 OKServer: nginxDate: Thu, 27 Feb 2014 09:25:41 GMTContent-Type: image/pngContent-Length: 1133Last-Modified: Fri, 14 Feb 2014 08:05:03 GMTConnection: keep-aliveETag: "52fdce2f-46d"Accept-Ranges: bytes

然后向服务器发送If-None-Match HTTP头

# curl -H 'If-None-Match: "52fdce2f-46d"' -I http://phalcon/img/css.pngHTTP/1.1 304 Not ModifiedServer: nginxDate: Thu, 27 Feb 2014 09:25:44 GMTLast-Modified: Fri, 14 Feb 2014 08:05:03 GMTConnection: keep-aliveETag: "52fdce2f-46d"

这次比较顺利,成功返回HTTP/1.1 304 Not Modified

3.2. 动态程序

默认情况输出如下

# curl -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginxDate: Thu, 27 Feb 2014 09:29:13 GMTContent-Type: text/html; charset=utf-8Connection: keep-alive

测试程序

Hello

测试效果

# curl -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 09:41:06 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Thu, 26 Feb 2014 08:39:35 GMTEtag: "abcdefg"[root@centos6 ~]# curl -H 'If-None-Match: "abcdefg"' -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 09:41:42 GMTContent-Type: text/htmlConnection: keep-aliveLast-Modified: Thu, 26 Feb 2014 08:39:35 GMTEtag: "abcdefg"

测试情况与之前的Last-Modified结果一样

动态程序返回Etag真的就没有用了吗?

答案是:非也, 有一个方法可以让动态程序返回的 Etag 也能发挥作用,程序修改如下

首先查看Etag值

# curl  -I http://192.168.6.9/test.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 10:07:19 GMTContent-Type: text/htmlConnection: keep-aliveEtag: 7467675324d0f7a3e01ce5151848fedb

发送If-None-Match头

# curl -H 'If-None-Match: 7467675324d0f7a3e01ce5151848fedb' -I http://192.168.6.9/test.phpHTTP/1.1 304 Not ModifiedServer: nginx/1.0.15Date: Thu, 27 Feb 2014 10:07:39 GMTConnection: keep-aliveEtag: 7467675324d0f7a3e01ce5151848fedb

达成预计效果,此种方法同样可以用于 Last-Modified,伪静态后效果更好

Etag 值的运算技巧,我习惯上采用URL同时配合伪静态例如

$etag = $_SERVER['REQUEST_URI']

URL类似 http://www.example.com/news/100/1000.html 一次请求便缓存页面,这样带来一个更新的问题,于是又做了这样的处理

http://www.example.com/news/100/1000.1.html

.1.是版本号,每次修改后+1操作,.1.没有人格意义rewrite操作是会丢弃这个参数,仅仅是为了始终有新的URL对应内容

4. Expires / Cache-Control

前面所讲 Last-Modified 与 Etag 主要用于分辨文件是否修改过, 无法控制页面在浏览器端缓存的时间。Expires / Cache-Control 可以控制缓存的时间段

Expires 是 HTTP/1.0标准,Cache-Control是 HTTP/1.1标准。都能正常工作,HTTP/1.1规范中max-age优先级高于Expires,有些浏览器会联动设置,例如你设置了Cache-Control随之自动生成Expires,仅仅为了兼容。

4.1. 静态文件

首先配置nginx设置html与png文件缓存1天

location ~ .*\.(html|png)${    expires      1d;}

当前情况

# curl -I http://192.168.6.9/index.htmlHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 10:47:08 GMTContent-Type: text/htmlContent-Length: 6Last-Modified: Thu, 27 Feb 2014 07:29:50 GMTConnection: keep-aliveAccept-Ranges: bytes

重启Nginx后的HTTP协议头多出Expires与Cache-Control

# curl -I http://192.168.6.9/index.htmlHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 10:42:09 GMTContent-Type: text/htmlContent-Length: 3698Last-Modified: Fri, 26 Apr 2013 20:36:51 GMTConnection: keep-aliveExpires: Fri, 28 Feb 2014 10:42:09 GMTCache-Control: max-age=86400Accept-Ranges: bytes

4.2. 动态文件

默认返回

# curl -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 11:45:05 GMTContent-Type: text/htmlConnection: keep-alive

index.php 增加 Cache-Control 输出控制

header('Cache-Control: max-age=259200');

再次查看

# curl -I http://192.168.6.9/index.phpHTTP/1.1 200 OKServer: nginx/1.0.15Date: Thu, 27 Feb 2014 11:53:48 GMTContent-Type: text/htmlConnection: keep-aliveCache-Control: max-age=259200

现在使用 Chrome 、Firefox 测试,你会发现始终返回200,并且max-age=259200数值不会改变。

原因是Cache-Control程序输出的,Nginx并不知道,所以Nginx 不会给你返回304

header('Last-Modified: ' .gmdate('D, d M Y H:i:s') . ' GMT' );$offset = 60 * 60 * 24;header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $offset) . ' GMT');$ttl=3600;header("Cache-Control: max-age=$ttl, must-revalidate");

这种方法不能实现缓存的目的

5. FastCGI 缓存相关

我们做个尝试将 expires 1d;加到location ~ \.php$中,看看能不能实现缓存的目的。

location ~ \.php$ {        root           /www;        fastcgi_pass   127.0.0.1:9000;        fastcgi_index  index.php;        fastcgi_param  SCRIPT_FILENAME  /www$fastcgi_script_name;        include        fastcgi_params;		expires      1d;    }

测试程序

# cat expires.php

测试结果

# curl -I http://localhost/expires.phpHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 04:39:57 GMTContent-Type: text/htmlConnection: keep-aliveExpires: Sat, 01 Mar 2014 04:39:57 GMTCache-Control: max-age=86400

虽然推送 Cache-Control: max-age=86400 但是 IE Chrome Firefox 仍不能缓存页面

6. HTML META 与 Cache

创建一个测试文件如下

	Hello	
Helloworld

测试HTML页面

# curl -i http://localhost/test.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 03:30:45 GMTContent-Type: text/htmlTransfer-Encoding: chunkedConnection: keep-alive	Hello	
Helloworld

我们可以看到HTML页面中meta设置缓存对Nginx并不起作用, 很多人会说对浏览器起作用!

这次我测试了 IE11, Chrome, Firefox 发现都无法缓存页面,可能对IE5什么的还有用,我没有环境测试,因为10年前我们在B/S开发经常这样使用

至少在当年IE是认这些Meta的,进入HTML5时代很多都发生了变化,所以不能一概而论

7. gzip

defalte 是 Apache httpd 的标准这里只谈gzip

首先创建一个 gzip.html

# curl -I http://localhost/gzip.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Mon, 03 Mar 2014 01:49:45 GMTContent-Type: text/htmlContent-Length: 19644Last-Modified: Mon, 03 Mar 2014 01:49:02 GMTConnection: keep-aliveETag: "5313df8e-4cbc"Accept-Ranges: bytes

开启 gzip on;

server {    listen       80;    server_name  localhost;    #charset utf-8;    #access_log  /var/log/nginx/log/host.access.log  main;    #etag on;    #ssi on;    gzip on;

现在看看效果

# curl -I http://localhost/gzip.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Mon, 03 Mar 2014 01:51:56 GMTContent-Type: text/htmlContent-Length: 19644Last-Modified: Mon, 03 Mar 2014 01:49:02 GMTConnection: keep-aliveETag: "5313df8e-4cbc"Accept-Ranges: bytes

并没有什么不同,现在增加HTTP头Accept-Encoding:gzip,defalte看看

# curl -H Accept-Encoding:gzip,defalte  http://localhost/gzip.html

如果你能看到非文本内容(俗称乱码)就表示成功了。输入内容就是gzip压缩后二进制数据,我们使用gunzip可以解压缩

# curl -H Accept-Encoding:gzip,defalte  http://localhost/gzip.html | gunzip

如果能正常看到html输出,表示压缩无误。

7.1. gzip 总结

gzip on; 开启后默认支持 text/html 不能在 gzip_types 再次定义,否则会提示重复MIME类型

Starting nginx: nginx: [warn] duplicate MIME type "text/html" in /etc/nginx/conf.d/localhost.conf:16

高级配置参考

gzip  on;    gzip_http_version 1.0;    gzip_types        text/plain text/xml text/css application/xml application/xhtml+xml application/rss+xml application/atom_xml application/javascript application/x-javascript application/json;    gzip_disable      "MSIE [1-6]\.";    gzip_disable      "Mozilla/4";    gzip_comp_level   6;    gzip_proxied      any;    gzip_vary         on;    gzip_buffers      4 8k;    gzip_min_length   1000;

8. 反向代理与缓存

反向代理服务器缓存方式分为:

强制缓存,指定文件,扩展名,URL设置缓存时间

遵循HTTP协议头标准进行缓存

默认配置,只进行代理,不进行缓存

server {    listen       80;    server_name  192.168.2.15;    #access_log  /var/log/nginx/log/host.access.log  main;	location / {	  proxy_pass        http://localhost:80;	  proxy_set_header  X-Real-IP  $remote_addr;	}}

反向代理会产生两条日志(access_log 写入一个文件中,如果分开写,则会分开写入日志)

192.168.2.15 - - [28/Feb/2014:18:09:33 +0800] "HEAD /modified.html HTTP/1.1" 200 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"127.0.0.1 - - [28/Feb/2014:18:09:33 +0800] "HEAD /modified.html HTTP/1.0" 200 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"

Last-Modified 与 ETag 会透传过去

# curl -H "If-Modified-Since: Fri, 28 Feb 2014 12:04:18 GMT" -I http://192.168.2.15/modified.htmlHTTP/1.1 304 Not ModifiedServer: nginx/1.4.5Date: Fri, 28 Feb 2014 10:17:30 GMTConnection: keep-aliveLast-Modified: Fri, 28 Feb 2014 10:04:18 GMT

我们可以看到两条日志都返回304

192.168.2.15 - - [28/Feb/2014:18:17:30 +0800] "HEAD /modified.html HTTP/1.1" 304 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"127.0.0.1 - - [28/Feb/2014:18:17:30 +0800] "HEAD /modified.html HTTP/1.0" 304 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"

下面为反向代理增加缓存功能

proxy_temp_path   /tmp/proxy_temp_dir;proxy_cache_path  /tmp/proxy_cache_dir  levels=1:2   keys_zone=nginx_cache:200m inactive=3d max_size=30g;server {    listen       80;    server_name  192.168.2.15;	location / {		proxy_cache nginx_cache;		proxy_cache_key $host$uri$is_args$args;		proxy_set_header  X-Real-IP  $remote_addr;		proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;		proxy_cache_valid 200 10m;		proxy_pass        http://localhost;	}	location ~ .*\.(php|jsp|cgi)?$	{	     proxy_set_header Host  $host;	     proxy_set_header X-Forwarded-For  $remote_addr;	     proxy_pass http://backend_server;	}}

# curl  -I http://192.168.2.15/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 10:57:35 GMTContent-Type: text/htmlContent-Length: 12Connection: keep-aliveLast-Modified: Fri, 28 Feb 2014 06:54:45 GMTETag: "531032b5-c"Expires: Sat, 01 Mar 2014 10:57:35 GMTCache-Control: max-age=86400Accept-Ranges: bytes# curl  -I http://192.168.2.15/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 10:57:41 GMTContent-Type: text/htmlContent-Length: 12Connection: keep-aliveLast-Modified: Fri, 28 Feb 2014 06:54:45 GMTETag: "531032b5-c"Expires: Sat, 01 Mar 2014 10:57:35 GMTCache-Control: max-age=86400Accept-Ranges: bytes# curl  -I http://192.168.2.15/index.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Fri, 28 Feb 2014 10:57:46 GMTContent-Type: text/htmlContent-Length: 12Connection: keep-aliveLast-Modified: Fri, 28 Feb 2014 06:54:45 GMTETag: "531032b5-c"Expires: Sat, 01 Mar 2014 10:57:35 GMTCache-Control: max-age=86400Accept-Ranges: bytes

上面共请求了3次服务器

192.168.2.15 - - [28/Feb/2014:18:57:35 +0800] "HEAD /index.html HTTP/1.1" 200 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"127.0.0.1 - - [28/Feb/2014:18:57:35 +0800] "GET /index.html HTTP/1.0" 200 12 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "192.168.2.15"192.168.2.15 - - [28/Feb/2014:18:57:41 +0800] "HEAD /index.html HTTP/1.1" 200 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"192.168.2.15 - - [28/Feb/2014:18:57:46 +0800] "HEAD /index.html HTTP/1.1" 200 0 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"

第一次连接192.168.2.15然后转发给127.0.0.1 返回 HTTP/1.1 200 OK

后面两次连接192.168.2.15没有转发给127.0.0.1 直接返回 HTTP/1.1 200 OK

查看缓存目录,我们可以看到生成的缓存文件

# find /tmp/proxy_*/tmp/proxy_cache_dir/tmp/proxy_cache_dir/1/tmp/proxy_cache_dir/1/79/tmp/proxy_cache_dir/1/79/b47a0009c531900de2a15ba80c0e3791/tmp/proxy_temp_dir

8.1. gzip 处理

http://localhost/gzip.html 是支持压缩的,192.168.2.15 proxy_pass http://localhost

# curl -H Accept-Encoding:gzip,defalte  http://localhost/gzip.html

运行后输出乱码

# curl -H Accept-Encoding:gzip,defalte  http://192.168.2.15/gzip.html

现在透过反向代理请求试试,你会发现gzip压缩无效,输出的是HTML,这是怎么回事呢?这是因为反向代理不清楚后面的服务器是否支持gzip,所以一律按照正常html请求。现在我们开启 gzip_vary on; 每次返回数据会携带Vary: Accept-Encoding 头。

gzip  on;	gzip_vary on;

reload nginx 后查看Vary: Accept-Encoding输出

# curl -I http://localhost/gzip.htmlHTTP/1.1 200 OKServer: nginx/1.4.5Date: Mon, 03 Mar 2014 02:09:16 GMTContent-Type: text/htmlContent-Length: 19644Last-Modified: Mon, 03 Mar 2014 01:49:02 GMTConnection: keep-aliveVary: Accept-EncodingETag: "5313df8e-4cbc"Accept-Ranges: bytes

有 Vary: Accept-Encoding 头,现在再测试一次

# curl -H "Accept-Encoding: gzip" http://192.168.2.15/gzip.html	Hello

测试失败,并没有出现预期效果,于是到网站找答案,中文与英文资料都看个遍,没有解决.

最后只能让反向代理取到数据后再压缩一次,配置开启 gzip on;

proxy_temp_path   /tmp/proxy_temp_dir;proxy_cache_path  /tmp/proxy_cache_dir  levels=1:2   keys_zone=nginx_cache:200m inactive=3d max_size=30g;server {    listen       80;    server_name  192.168.2.15;	gzip on;		location / {		proxy_set_header X-Real-IP  $remote_addr;		proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for; 		# proxy_set_header Accept-Encoding "gzip"; 没有任何效果		proxy_pass       http://localhost;	}}

Nginx 反向代理作为代理绰绰有余,如果做缓存服务器,还是使用squid, varnish吧。

9. 特殊数据缓存

缓存并非只能缓存静态内容,HTML,CSS,JS以及图片意外的数据一样可以缓存。

只要处理好HTTP头即可。例如Ajax动态内容缓存,JSON数据缓存。

9.1. json

当用户请求json地址时,我们将 json 数据附加HTTP头(Cache-Control, Expires, ETag),然后返回给用户,用户的设备会遵循HTTP的声明,进行缓存操作。

curl -I http://api.example.com/article/json/2/20/0.htmlHTTP/1.1 200 OKExpires: Wed, 26 Aug 2015 05:40:57 GMTDate: Wed, 26 Aug 2015 05:39:57 GMTServer: nginxContent-Type: application/json; charset=utf-8Transfer-Encoding: chunkedCache-Control: max-age=60ETag: 4238111283Age: 69475X-Via: 1.1 kaifeng45:3 (Cdn Cache Server V2.0)Connection: keep-alive

注意这里使用了伪静态 /article/json/2/20/0.html 伪静态与缓存没有关系,实际起作用的是HTTP头。

我们可以看到 Content-Type: application/json; charset=utf-8 声明,表明这是json数据,而不是HTML。

9.2. XML

这里是指动态生成的XML,处理方式与 JSON一样,XML数据附加HTTP头(Cache-Control, Expires, ETag)后返回给用户。

10. 总结

经过详细的测试我们发现不同的浏览器,不同的Web服务器,甚至每个版本都有所差异。

测试总结 Apache HTTPD 最完善 Lighttpd 其次, Nignx仍在快速发展中,Nignx每个版本差异很大,对HTTP协议实现标准也不太严谨,因为Nignx在大陆是趋势,所以下面给出的例子都是nginx

我比较看好Lighttpd,FastCGI 部分我一般是用php-fpm替代Lighttpd的spawn-fcgi

切记使用Nginx要注意每个本版细微变化,否则升级后会有影响。我习惯使用yum 安装 nginx 随时 yum update 升级。

另外FastCGI 与 mod_php也有所区别

延伸阅读《 Netkiller Web 手札》

084042_HzOA_725072.jpg

转载于:https://my.oschina.net/neochen/blog/497690

你可能感兴趣的文章
正则表达式小结
查看>>
使用CSS处理标题过长,自动截断,兼容响应式布局
查看>>
php 调试利器debug_backtrace()
查看>>
Hexo-Neat介绍
查看>>
细说C#:委托的简化语法,聊聊匿名方法和闭包(上)
查看>>
Elixir Ecto: 使用 ExMachina 批量生成测试数据
查看>>
虚拟机类加载机制(读书笔记)
查看>>
PHP学习计划
查看>>
[稀土掘金日报] JavaScript 开发者必备的资源合集
查看>>
Win软件私家珍藏-常用软件工具使用总结
查看>>
iToolkit,推荐我们自己做的一套前端组件
查看>>
Junit源码阅读(一)
查看>>
首席信息安全官的未来将何去何从?
查看>>
JS中的二叉树遍历
查看>>
JavaScript设计模式与开发实践 | 01 - 面向对象的JavaScript
查看>>
为什么要阅读Tornado的源码?
查看>>
Linux基础命令---bzcat
查看>>
洛谷 P3369 BZOJ 3224 【模板】普通平衡树(Treap/SBT) ...
查看>>
2019年2月值得一读的10本技术书籍(Python、算法、设计、历史等书籍)! ...
查看>>
LinkedHashMap 详解
查看>>