网站日记:解决wordpress中文url无法访问404的方法

网站日记:解决wordpress中文url无法访问404的方法

在建站以来,一直到今天为止,我的wordpress网站仍然无法打开包含中文字符的url,返回404。这个问题我搜索了很多答案,发现只要是使用apache2搭建的wordpress站点,就几乎都会出现这种情况。本文提出一种原创的,可以完美解决上述问题的方法。转载请见文末版权声明。

网站环境

请确保你的网站和我使用相同的环境,否则本文提出的方案可能不具有参考意义。

  • web服务器:Apache2
    我的同学使用Nginx,并不会出现中文url问题。
  • 网站程序:wordpress + php7
  • 操作系统:Ubuntu 18.04

问题原因

这是wordpress的设计问题,这个程序主要面向英语使用者,因此对中文或其他语言的兼容性不佳。

wordpress使用伪静态的方式来链接php页面,举个例子:

https://www.robertliang.club/wp-admin/post.php?post=209

这是伪静态链接背后的面目。了解php的同学可能知道,‘?’后面跟的内容是传递给php文件的参数。那么这个页面实际上的链接意思就是打开post.php文件,同时给这个文件传入post=209这个参数,让他知道自己应该显示哪一篇文章。

但是,这个链接非常不利于人们记忆或理解,也不利于搜索引擎识别。因此wordpress采用伪静态链接的方式将这个页面重定向到:

https://www.robertliang.club/index.php/computerscience/computer-tool/read-and-conclusion-gpl/

这个重定向的规则较为复杂,我们没必要研究清楚。

出现404问题的原因在于,wordpress在这个重定向的过程中,在php文件中设定的服务器参数$_SERVER[‘PATH_INFO’]等参数存在并非UTF-8编码的问题,因此重定向后的request路径编码格式不对。(大概是这样的……我也不是太确定,如不对请指出)

其他人的解决方案

在解决这个问题的过程中,我也是调研了很多的解决方案,它们都有不足,这里简单列举,不再援引出处。

修改php配置文件法

有两种方式,第一种方式是修改wordpress程序中的wp_class.php等一众文件。 这是最为直接的一种解决方法,直接填补了wordpress设计者在兼容性上的不足。缺点是:1.需要理解php源代码,操作难度较高。2.对应不同wordpress版本操作方法并不相同,不具备概括性。3.wordpress的更新会覆盖掉这些‘主要文件’。

第二种方式是在wp-config.php中修改PATH_INFO参数,这种方法是本文解决方案的基础,后面详细讲解。优点是config文件不会有版本更新问题,一劳永逸。缺点是例如yoast-seo插件依赖于这个参数,导致sitemap出错,但可以修复

插件法

经过调研,确实是有插件可以解决上述问题的,但是:1.这个插件更适用于IIS,而非apache,兼容性未知。2.此插件已经很久没有更新,然而对于他的依赖性却无法替代。3.用这个办法,你学不到东西。

Rewrite法(Apache2配置URL改写)

这个方法虽然本文并没有采用,但对于整体的解决方案有很大的启发。采用这个方法的原理就是通过配置apache2的url改写规则,来代替php程序中的改写规则。缺点:1.Rewrite是apache中的一个较复杂的模块,并不算易于学习。2.wordpress php程序中的伪静态规则复杂,Rewrite方法实现困难。

这里简单举一个例子。将 domain/index.php/tag/原创 重定向到 domain/index.php?tag=原创。它的实现代码下方已经给出,由于后面会介绍类似内容,这里不再详述。

RewriteRule /tag/(.*)/$ /index\.php\?tag=$1

如前文所述,这确实可以解决‘标签’中文url的问题,然而‘文章’,‘页面’等伪静态规则远比这复杂,使用Rewrite法就会困难得多。

我的‘一劳永逸’解决方案

由于我个人认为这个方案需要一定的背景和基础,因此我将在适当的情况下补充一些背景知识。

Overview

我画了一个流程图,以供读者大致了解整个处理过程。

修改PATH_INFO变量

  1. 打开wp-config.php文件,在这个文件修改的好处是他不会被wordpress更新所覆盖。
  2. 在文件的末尾,插入代码。
/** 修改PATH_INFO为空,这样wordpress在处理伪静态的时候,会主动找替代方案,
* 这就解决了PATH_INFO编码格式问题 */
$_SERVER['PATH_INFO']='';

这样修改过后,再次访问网站的中文地址,应该已经可以访问了。但同时带来了其他问题,请往下看。

检查sitemap是否异常

我使用的是Yoast-SEO插件,这是wordpress数一数二的SEO插件,它可以生成xml格式的站点地图,供搜索引擎抓取网站内容。

以本站sitemap为例

我发现,进行上一步操作之后,这里的sitemap已经无法打开了(404)。原因个人猜测原因是这个插件的伪静态重定向需要PATH_INFO变量,然而这个变量被我们设置为空,这并不重要。因此接下来需要置顶Rewrite规则修复这个问题。

Rewrite方法解决sitemap无法访问

选取你的Rewrite方法

先贴出apache2的官方文档——Rewrite。(后续如果必要,我考虑写一篇“阅读与理解”)

对于我(服务器的root)而言,制定Rewrite规则有两种方式。

  • 直接在主配置文件(ubuntu下为 /etc/apache2/apache2.conf ,其他系统apache2主配置文件在 /etc/apache2/httpd.conf )进行制定。这种方法具有更高的效率和响应速度缺点是集中式的配置会略显凌乱,且有些站主无权访问这个文件。
  • 通过分布式配置文件.htaccess来进行规则制订。分布式配置文件即这个文件所在的目录及其包含的所有目录下,都适用于这个文件的配置。你只需要在wordpress根目录上传.htaccess文件即可缺点,速度慢效率低
  • 这两种方式的Rewrite写法是完全一致的

安装Rewrite模块

Rewrite是apache2自带的一个模块,但一般情况下并没有启用他。ubuntu下apache2自带的模块放在 /etc/apache2/mods-available/ 下,启用的模块通过动态链接放在 /etc/apache2/mods-enabled/ 下。

启用Rewrite模块可以使用a2enmod命令。

#linux shell:
sudo a2enmod rewrite

反馈为 Module rewrite has been enabled.

直接在主配置文件中制定Rewrite规则

先上代码。打开apache2的主配置文件 /etc/apache2/apache2.conf(ubuntu)
添加以下内容。(附:ubuntu下更好的配置文件方法

#Directory块的作用是指定它包含的配置指令适用的范围,其中/var/www/html是我的wordpress在服务器上的主目录。
<Directory "/var/www/html"> 
   #开启Rewrite实时改写url功能
   RewriteEngine On
   #指定Rewrite规则,将前者的访问请求改写成后者的形式。
   RewriteRule ^index\.php/sitemap_index\.xml$ /index.php?sitemap=1 [L]
   RewriteRule ^index\.php/(.+)-sitemap\.xml$ /index.php?sitemap=$1 [L]
</Directory>

上面比较难以理解的是RewriteRule 指令,它的语法规则请详见apache2官方文档,大致上是Rewrite Pattern Substitution [Flags]其中Pattern是正则表达式,与访问请求的URL进行匹配,如果匹配成功,则将其改写到Substitution。

上面的第一条规则是将 https://www.robertliang.club/index.php/sitemap_index.xml 改写到 https://www.robertliang.club/index.php?sitemap=1

第二条规则是将 https://www.robertliang.club/index.php/任意字符串-sitemap.xml 改写到 https://www.robertliang.club/index.php?sitemap=任意字符串

这里substitution$1是一个变量,学名叫back-reference,它引用的是Pattern中匹配的的url请求第一个(括号)中的内容

为什么要这么改写?这其实是代替了Yoast-SEO自己的[已经失常的]php改写规则。

详情见附:Yoast-SEO sitemap 结构

Flags是一些额外的参数,譬如[L]代表的是这条RewriteRule是最后一条,不与其后的RewriteRule并列执行。

在分布式配置文件.htaccess中制定Rewrite规则

在.htaccess中制定对于某些站主来讲可能是唯一的方法。因为他们并没有权限访问apache2的主配置文件。但是他们要确保.htaccess文件可以生效,这就要求在主配置文件(/etc/apache2/apache2.conf 适用于ubuntu,附:ubuntu下更好的配置文件方法)中要有这样一句话:

AllowOverRide all
#这条directive允许在主配置文件外,分布式配置文件.htaccess的使用。

那么回到你的wordpress主目录,touch .htaccess创建分布式配置文件,打开它,写入Rewriterule即可。

   #开启Rewrite实时改写url功能
   RewriteEngine On
   #指定Rewrite规则,将前者的访问请求改写成后者的形式。
   RewriteRule ^index\.php/sitemap_index\.xml$ /index.php?sitemap=1 [L]
   RewriteRule ^index\.php/(.+)-sitemap\.xml$ /index.php?sitemap=$1 [L]

对于这一段代码的解释,前文已经非常详细了。(参考:直接在主配置文件中制定Rewrite规则

最后一步&测试

最后一步是保存你的配置文件,然后重启apache:sudo service apache2 restart。此时你的yoast SEO就应该已经可以正常工作了,你可以在浏览器测试一下https://yourdomain/index.php/sitemap_index.xml能否正常打开?

或许还有其他的插件也无法正确的显示他的链接。但是你已经掌握了修复它的方法,我想这对你来说已经不再是一个问题。

附:Yoast-SEO sitemap 结构

前文提到通过rewrite方法将sitemap从为静态url改写到它真正的php链接。这里就不得不提一下Yoast-SEO 的sitemap结构。

首先是sitemap_index.xml,它的伪静态链接地址是https://www.robertliang.club/index.php/sitemap_index.xml。实际地址是 https://www.robertliang.club/index.php?sitemap=1

我们看到在sitemap主页下有多个分支的sitemap,他们的数量并不一定是固定的,因为额外的插件也会引入分支(譬如ngg_tag,是我的nextgen gallery的标签)。但好在他们的地址都有相同的形式,以post为例,它的实际地址为https://www.robertliang.club/index.php?sitemap=post

由于它们具有相同的格式,因此可以用一条Rewriterule一劳永逸的将他们全部改写。

sitemap的结构和实际地址是我自己摸索出来的,实际上更为合理的获取方式是阅读yoast-SEO插件的php源码,这对php基础又有所要求。

附:ubuntu下更好的配置文件方法

ubuntu下的apache2配置文件与其他linux发行版安装的apache2文件不同。它具有树状的结构,这里我不再介绍,事实上在安装好apache2后,web服务器的documentroot目录下的index.html已经有很好的解释了。

与前文提到的mods-available mods-enabled目录一样,它的配置文件也有conf-available conf-enabled目录。所以我认为更清楚地管理他的配置文件的方式是:

  1. 在/etc/apache2/conf-available中新建一个子配置文件subconfig.conf
  2. 添加你想要的指令。
  3. 在linux shell中使用a2enconf命令来启用这个配置文件sudo a2enconf subconfig
  4. 重载apache2sudo service apache2 restart

附:Google search console “无法获取”站点地图

这个问题说来有些惭愧,百度资源的sitemap收录就不会有这个问题。总而言之,在google search console提交sitemap的时候,还是提交实际地址而非rewrite地址就好了。看图


CC-BY-NC-SA

The solution by RobertLiang is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license.
在这个解决方案基础上的派生方案,请尽量让我知晓,以便进步。Please let me know your derivative of this solution, so that I can make progress.

RobertLiang

A post-graduate in USTC.

目前为止有一条评论

网站日记:第一次正式地被百度收录 – 罗伯特梁的网站 发布于下午2:22 - 2020年6月28日

[…] 网站日记:解决wordpress中文url无法访问404的方法 […]

You must be logged in to post a comment