Skip to main content

Joomla开启全站CDN之前要做的工作——修改http headers

一个Joomla网站,如果学着一般网站的样子去开启全站CDN加速,在CDN生效之后,有很大可能,会感觉到网站的加载速度变慢了。敲着锣鼓唱着歌,欢天喜地的打开一个测试网站访问速度的地方,期待看到下面的画面:

网站访问速度测试

然而,实际上却可能是下面的样子:

网站访问速度测试

究其原因是因为Joomla强大的权限设置功能,它可以对不同的用户展示不同的网站内容,这些用户包括:Public, Guest, Registered, Special和Super Users,这就意味着同一个url可能会有若干个内容不同的网页。因此,Joomla不同于常见的内容发布系统(Wordpress),它对于缓存这种东西是很“抵制”的。访问一个默认安装的Joomla网站,用开发者工具检查http header,会找到下面的结果:

P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Expires: Wed, 17 Aug 2005 00:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

上面的http header从简单的方面说,就是Joomla用尽各种headers告诉用户的浏览器——不要缓存我的页面!

下面举个例子:

  • 情况一,用户刚刚浏览了网页A,点击A里面的超链接来到了网页B,再点击浏览器的后退按钮,从B退回到网页A,一般情况下,浏览器不会去服务器再次下载网页A,而是直接读取网页A在浏览器里面的缓存,这个过程会非常的迅速;
  • 但如果把这个例子放在Joomla上——情况二,Joomla会强迫浏览器去找服务器要一份网页A的最新版本,哪怕网页A一点改动都没有。这个过程除了增加一点服务器和客户端的开销以外,并不算是个问题。可是,一旦Joomla网站开启全站CDN加速的话,这就是一个大问题!

继续刚才的例子,假设网站开启了全站CDN加速。情况一,在客户访问网页A和网页B之后,这两个网页将被CDN缓存,以后不管客户在两个网页之间怎么浏览过来浏览过去,都是由CDN提供页面给客户,速度会非常的快。这种“客户《====》CDN”的传输模式正是CDN存在的意义。

情况二就不一样了,CDN会读取到Joomla的http headers,并遵守,所以CDN不会缓存Joomla页面。当客户访问网页A,CDN发现缓存里没有,就去源网站服务器里取一份A,传输给客户,这时候的CDN只相当于一个代理中介,站在客户和网站服务器中间。当客户再次访问A的时候,由于CDN不会缓存Joomla页面,所以CDN里面还是没有网页A,就再到源网站服务器里取一份A,然后传输给客户。所以,现在的传输模式是“客户《====》CDN《====》网站服务器”。

cdn传输路线

多一个香炉多一个鬼。在服务器自身状态良好的情况下,只要不是什么国际性网站,那么“客户《====》CDN《====》网站服务器”这种传输模式的速度比“客户《====》网站服务器”慢。于是,网站在开启CDN加速后的速度测试结果,就会出现上面图片中全国山河一片红的情况。

如果某个Joomla站点,只是做内容展示用的,没有会员系统,没有互动和社交,没有即时性的内容,那么,这样的网站就适合开启全站CDN加速(比如各大企业站点),在这种情况下,Joomla程序自带的http headers就成了一种没必要的负担。因此,在开启全站CDN之前,需要对Joomla的http headers进行修改。

仔细研究了一下Joomla代码,找到了形成上面no-cache http headers的文件,libraries/src/Application/WebApplication.php ( Joomla 3.9.x ) ,代码列举如下:

// If the response is set to uncachable, we need to set some appropriate headers so browsers don't cache the response.
if ( !$this->response->cachable ) {
// Expires in the past.
$this->setHeader( 'Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true );

// Always modified.
$this->setHeader( 'Last-Modified', gmdate( 'D, d M Y H:i:s' ) . ' GMT', true );
$this->setHeader( 'Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false );

// HTTP 1.0
$this->setHeader('Pragma', 'no-cache');

由于上面代码的存在,Joomla能够覆盖掉apache服务器里面的mod_headers和mod_expires设置,这不是我们想要的结果。我们可以简单的注释掉上面的代码,让apache mod_headers来接管,这样的做法简单有效。但是,该文件有可能在更新Joomla程序的时候,被覆盖回来,每次升级的时候都需要特别注意一下。我们也可以用一个一劳永逸的方法,装一个插件——Expires Headers。安装-启用,设置如下:

Joomla plugin Expires Headers

你现在看到的这个网站 http://chengduwangluo.com/ ,为了覆盖Joomla自身的http headers,用的也是Expires Headers这个插件(有兴趣的话可以F12去看看),不过我并不是为了去开启全站CDN加速,因为我还没有工信部备案……

按照我上面的设置,CDN访问网站页面之后,会缓存页面一个月,在这个期间内,再有用户浏览器发起请求的时候,都会由CDN来负责,达到我们想要的加速效果——“客户《====》CDN”。