解决Fastcgi_cache移动版与Web版缓存混乱问题

  1. 1. cache原理
  2. 2. 缓存更新
  3. 3. 缓存混乱问题
  4. 4. WP开启多域名支持
  5. 5. Nginx UA跳转判断
  6. 6. 其他问题

最近启用了Fastcgi_cache,这货的确蛮给力的,速度非常快

cache原理

本来是用户请求,然后通过如下一堆处理过程,把页面返回给用户

而开启fastcgi cache后,用户第一次请求,会把返回的文件同时缓存起来,如果再有请求,命中缓存直接从cache返回数据,省去了fastcgi和php通信处理过程

开启Fastcgi cache后相当于全站静态了,可以到缓存文件夹查看缓存文件,这些文件没有加密,文本保存的,就是一个网页的html代码

Nginx对静态文件的处理还是非常给力的,当然你的disk也要给力啊

不过响应的问题也有一些,例如Fastcgi_cache不会去检测php是否更新,所以如果有内容更新后页面不会更新,这个很蛋疼

缓存更新

对于wordpress来说要解决这个问题还是很简单的,一般更新就两种,一种发表新文章,这种没关系,肯定是新生成缓存,而评论fastcgi cache就不会更新

对于这个问题我有一个比较粗暴的解决方法,就是用脚本实时扫描Nginx的日志,一旦有对comment-post.php的post请求,就把请求地址返回,并找到对应缓存文件删除,这样就保证更新了,至少我博客没啥特别的功能,只需要评论能更新就ok

缓存更新脚本介绍请看这里《Wordpress的fastcgi cache缓存更新脚本》

缓存混乱问题

但还有个严重的问题,由于配置Fastcgi cache时我的key配置为$request_method$scheme$host$request_uri

一般都会这么配,生成的key就例如GET HTTP http://xfeng.me/about ,问题就来了

现在很多人都是用wptouch这类插件来生成移动版博客,请求url完全相同,但是返回页面不同,而使用了Fastcgi cache后,如果手机先访问了一个还没生成缓存的页面,这时生成的缓存是移动版页面,当电脑去请求同意url时,由于缓存命中,直接返回缓存,电脑也查看到移动版页面

这个问题很蛋疼了,开始我吧$http_user_agent也放到key里,例如$http_user_agent$request_method$scheme$host$request_uri

这样的确能解决问题,但是UA千变万化,每个UA都要重新生成一次缓存,除非是回访,新来访者几乎失去了缓存的意义

因此我想出了下面蛋疼的解决办法,这个办法并不是最好的,也有一些问题,具体的后面再说,先介绍我的解决方案

移动版和Web版缓存混乱是由于cache key相当引起的,解决方案肯定是把key区分开,把key加入UA这种方法已经排除了,那么只能改变host或者使用两个不同的缓存空间

变host就会出现两个域名,电脑访问xfeng.me,而手机访问m.xfeng.me

但为了让用户之前一样,完全智能返回对应版本的页面,就需要在Nginx上做些判断了

WP开启多域名支持

不过首先需要让wordpress支持多域名,因为我们需要两个域名同时访问一个wordpress系统,方法很简单,只需要在你的wp-config.php里加入如下配置

1
2
3
4
$home = 'http://'.$_SERVER['HTTP_HOST'];
$siteurl = 'http://'.$_SERVER['HTTP_HOST'];
define('WP_HOME', $home);
define('WP_SITEURL', $siteurl);

加入上面的代码后,你博客后台配置URL那栏就会禁止配置了,根据请求域名来判断,当然,你需要把你的移动版域名解析到你的服务器上

Nginx UA跳转判断

开启多域名支持后,就需要修改Nginx配置了,我们需要新增一个server,然后在原来的server里加入UA的判断,把移动设备的请求转到m.xfeng.me,而把非移动设备的请求都转回到xfeng.me

配置如下,我只贴出了相关部分,这不是完整的配置,你需要把需要的部分补齐到你的配置里

1
http
    {
		fastcgi_temp_path /tmp/ngx_fcgi_tmp;
		fastcgi_cache_path /tmp/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:128m inactive=5m max_size=1g;
		fastcgi_cache_valid 200 1h;
		fastcgi_cache_valid 302 1h;
		fastcgi_cache_valid 301 1d;
		fastcgi_cache_valid any 1m;
		fastcgi_cache_min_uses  1;
		fastcgi_cache_use_stale error timeout invalid_header http_500;
		fastcgi_cache_key "$request_method$scheme$host$request_uri";

		server
			{
				listen       80;
				server_name xfeng.me;
				index index.html index.htm index.php;
				root  /www/xfeng.me;

				if ( $http_user_agent ~*  "^((.*MIDP.*)|(.*WAP.*)|(.*Mobile.*)|(.*CLDC.*)|(.*Googlebot-Mobile.*)|(.*iPhone.*)|(.*Android.*)|(.*iPad.*)|(.*ios.*)|(.*Symbian.*)|(.*Nokia.*)|(.*Windows CE.*)|(.*blackberry.*)|(.*SonyEricsson.*)|(.*webOS.*)|(.*Windows Phone.*)|(.*Maemo.*)|(.*Meego.*)|(.*Opera Mobi.*)|(.*Opera Mini.*)|(.*Palm.*)|(.*UCWEB.*)|(.*BenQ.*)|(.*PHILIPS.*)|(.*SAMSUNG.*)|(.*Lenovo.*)|(.*Mitsu.*)|(.*Motorola.*)|(.*SHARP.*)|(.*WAPPER.*)|(.*LG.*)|(.*Dopod.*)|(.*Haier.*)|(.*ZTE.*))$" )
					{
						rewrite ^/(.*)$ http://m.xfeng.me/$1 redirect;
					}

				location ~ .*\.(php|php5)?$
					{
						fastcgi_pass  unix:/tmp/php-cgi.sock;
						fastcgi_index index.php;
						include fcgi.conf;
						fastcgi_cache ngx_fcgi_cache;
					}
			}
		server
			{
				listen       80;
				server_name m.xfeng.me;
				index index.html index.htm index.php;
				root  /www/xfeng.me;

				if ( $http_user_agent !~*  "^((.*MIDP.*)|(.*WAP.*)|(.*Mobile.*)|(.*CLDC.*)|(.*Googlebot-Mobile.*)|(.*iPhone.*)|(.*Android.*)|(.*iPad.*)|(.*ios.*)|(.*Symbian.*)|(.*Nokia.*)|(.*Windows CE.*)|(.*blackberry.*)|(.*SonyEricsson.*)|(.*webOS.*)|(.*Windows Phone.*)|(.*Maemo.*)|(.*Meego.*)|(.*Opera Mobi.*)|(.*Opera Mini.*)|(.*Palm.*)|(.*UCWEB.*)|(.*BenQ.*)|(.*PHILIPS.*)|(.*SAMSUNG.*)|(.*Lenovo.*)|(.*Mitsu.*)|(.*Motorola.*)|(.*SHARP.*)|(.*WAPPER.*)|(.*LG.*)|(.*Dopod.*)|(.*Haier.*)|(.*ZTE.*)|(.*Mediapartners-Google.*)|(.*Adsbot-Google.*))$" )
					{
						rewrite ^/(.*)$ http://xfeng.me/$1 redirect;
					}

				location ~ .*\.(php|php5)?$
					{
						fastcgi_pass  unix:/tmp/php-cgi.sock;
						fastcgi_index index.php;
						include fcgi.conf;
						fastcgi_cache ngx_fcgi_cache;
					}
			}
	}

简单解释下上面的配置,fastcgi_cache_path是指定缓存空间路径,缓存空间名,空间大小等信息

fastcgi_cache_path只能写在http段里,不能写在server里,开始我写到了server里,检查配置报错,后来在官方wiki里看了解释,HttpFcgiModule Wiki

fastcgi_cache_key是配置你的key,也就我文章开始说的key,也就是因为key相同才会造成移动版缓存混乱

fastcgi_cache就是启用缓存,后面跟你要用的用的缓存空间,你可以用fastcgi_cache_path定义多个缓存空间

开始我想在server里用if判断UA,不同的UA启用不同的缓存空间,但是Nginx不允许把fastcgi_cache 写到if判断里

其他几项fastcgi_cache参数不多介绍了,网上很多文章介绍很详细

上面的配置里有两个server,分别是xfeng.me和m.xfeng.me,两个server里都有一个if判断UA,然后302跳转

1
if ( $http_user_agent ~* ".*mobile.*" ) #这里就是判断是否为移动设备UA,不区分大小写
{
rewrite ^/(.*)$ http://m.xfeng.me/$1 redirect; #把移动设备302跳转到m.xfeng.me,请求地址不变
}
if ( $http_user_agent !~* ".*mobile.*" ) #判断是否不为移动设备UA
{
rewrite ^/(.*)$ http://xfeng.me/$1 redirect; #把非移动设备的请求302跳转到xfeng.me,请求地址不变
}

在两个server里都启用fastcgi cache,你可以使用同一个缓存空间,因为cache key已经不同了

这样就能保证在相同的请求地址下,自动返回对应设备的页面,并且缓存不会混乱,也只需要两份缓存

不过两个域名但内容完全相同,可能会被搜索引擎认为重复内容惩罚,不过对于Google还好说,因为Google针对移动版有专门的bot,Googlebot-Mobile加入到if判断里就好,别的搜索引擎就没办法了

其他问题

另外,wptouch在页面底部还有一个切换到Web版的开关,你可以去掉这个按钮了,除非你的移动设备浏览器支持伪装UA,伪装为电脑的才能访问Web版

去掉这个按钮只需要修改wptouch/theme/defuat/footer.php,去掉下面的代码

1
2
3
4
5
<center>
<div id="wptouch-switch-link">
< ?php wptouch_core_footer_switch_link(); ?>
</div>
</center>

完成上面的步骤,reload nginx,删掉旧的所有缓存文件,你的博客就开始正常工作了

不过我自己还有个小问题,也就是我的移动版有两个,一个是触屏版,用wptouch生成,另一个是非触屏版,用mobilepress生成,这两的页面缓存也会混乱

当然可以使用相同的办法,建第三个server,例如wap.xfeng.me,同样的if判断UA,把不同设备的UA分别跳转,不过不想这么折腾了,禁用了mobilepress

全部使用wptouch,虽然这样对一些旧的非触屏手机很不友好,因为wptouch很多东西是js的,就手机支持非常不好,例如我的E71就看着很不爽

最后,我现在已经停用上面的方案了,主要我的博客其实根本没多大访问量,没必要这么缓存,只是学习研究下fastcgi cache,并且把自己折腾的解决方案贴出来

开始弄好的时候,发现移动版缓存问题时,网络上找不到相关的文章,不知道是没多人用fastcgi cache生成wordpress的缓存还是怎么的

不过建议一般的小博客,例如我这类的还是不要用着东西了,虽然很快,不过由于缓存不智能,需要自己写脚本去清楚已经更新页面的缓存,还是那种访问量较大,并且更新不多的网站用比较好

声明: 除非注明,小峰网络遨游记文章均为原创,转载请以链接形式标明本文地址

本博客原创文字只代表本人某一时间内的观点或结论,与本人所在公司没有任何关系。

本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

第三方若用于商业用途的转载,须取得本人授权。

本文作者:

本文地址:http://xfeng.me/solve-fastcgi-cache-wp-mobile-confusion/

你可能还对下面文章感兴趣: