熟悉 WordPress 的都知道,在 Apache 主机上,并且 Apache 开启 AllowOverride 的情况下,WordPress 可以非常方便地设置固定链接。不论 WordPress 是安装在网站根目录还是二级目录下,都可以正常使用。
这得益于 Apache 的“分布式配置”机制,也就是 .htaccess 文件。
通过 .htaccess,可以非常方便地对当前目录下的 Apache 设置进行修改,包括伪静态规则、访问权限等。
当安装 WordPress 后,网站会自动在当前安装目录生成 .htaccess 文件,用来把网站的 URL 处理交给 WordPress。
但是到了 Nginx 下,事情就没有这么方便了。
Nginx 官方一直没有采用这种分布式配置的方式,因为这种方式会带来额外的资源消耗。
那么,在 Nginx 主机下,怎么样才能让 WordPress 实现和 Apache 下类似的固定链接效果呢?
其实核心就是解决伪静态的问题。
Apache 下的 .htaccess
先来看一下 WordPress 在 Apache 下常见的 .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
这里的意思其实很简单。
首先,如果访问的是 index.php,直接处理。
然后,当访问其他文件或者目录时,先判断这个文件或者目录是否真实存在。
如果存在,就直接访问。
如果不存在,则把请求交给:
来处理。
这样一来,网站上已经存在的文件和目录可以正常访问,而那些实际不存在的 URL,则交给 WordPress 的 index.php 进行处理。
例如访问 WordPress 文章的固定链接时,WordPress 可以根据 URL 查询数据库并返回对应文章;如果请求不存在,则可以由 WordPress 生成自己的 404 页面,而不是直接使用服务器默认的 404 页面。
Nginx 下的 WordPress 伪静态
那么到了 Nginx 下应该怎么设置呢?
在研究这个问题之前,网上已经可以找到不少解决方案,大致都是下面这种方式:
location / {
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
}可以看到,这样配置起来实际上比较麻烦。
特别是在一个站点下面存在多个 WordPress 目录的时候,每个目录都需要进行单独配置,而且规则比较多,也比较容易出错。
那么有没有更简单的方法?
前几天研究 Nginx 的 try_files 指令时,我发现它实现的功能和 WordPress 的要求刚好比较接近。
它可以依次判断:
- 请求的文件是否存在;
- 请求的目录是否存在;
- 如果都不存在,则交给指定的文件处理。
这和 WordPress 需要的处理方式基本一致。
所以,我们可以直接用下面这一行代码替换前面的多行规则:
try_files $uri $uri/ /index.php;
整个过程就变得非常简单:
经过测试,WordPress 的各项功能运行正常。
一个遗留的问题
不过还有一点比较遗憾。
由于 Nginx 运行 FastCGI 时的相关设置,所有以 .php 结尾的文件都会交给 FastCGI 进行处理,不论这个 PHP 文件是否真实存在。
因此,如果访问网站上一个不存在的 PHP 页面:
/abc.php
那么最后返回的可能是 FastCGI 生成的 404 页面,而不是 WordPress 自己生成的 404 页面。
这一点,前面网上找到的那种配置方式同样没有很好地解决。
即使如此:
try_files $uri $uri/ /index.php;
这一行配置也比前面的多条规则简单明了得多,而且不容易出错。
所以,在当时的实际测试中,我更推荐使用这种方式来处理 WordPress 在 Nginx 下的固定链接问题。
至于访问不存在的 PHP 文件时,如何让 WordPress 最终显示自己的 404 页面,这个问题还需要进一步研究。
关于访问不存在的PHP文件时,返回的不是Wordpres自定义404页面的问题已经解决,PHP这样配置即可
location ~ \.php$ {
try_files $uri /index.php;
fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
评论0
欢迎分享你的看法,也欢迎补充不同的实践经验。