Total Pageviews

Saturday 14 October 2017

解决 WordPres 子目录的404错误

最近博客换了空间,还原数据库和文件后发现有些子目录访问不能访问,出现404错误。费劲周折终于解决了这个问题,把原理和过程写下来,希望能给遇到同样问题的朋友提供一个参考。
我把WordPress装在根目录,假设为public_html,然后再建子目录存放子站,最终的目录结构形如:
# WordPress root
public_html/
# Subdomain 1
public_html/subdir1/
# Subdomain 2
pubic_html/subdir2/
测试发现有些子目录能访问,有些不能;更离奇的是WordPress自带的目录wp-includes竟然都不能访问!而wp-content, wp-admin却正常!
首先怀疑htaccess的问题,删除后果然一切正常。于是逐条排除htaccess的规则,最终定位在WordPress的Permalinks规则上。我们先来分析一下:

# BEGIN WordPress
# 中文部分为我加的注释,请勿拷贝到你的htaccess中
<IfModule mod_rewrite.c>
    # 开启重写
    RewriteEngine On
    # 定位更目录
    RewriteBase /

    # 规则1: 如果URI(Uniform Resource Identifier,即Domain后面的部分)为/index.php
    # 那么立即跳出重写规则
    RewriteRule ^index\.php$ - [L]

    # 规则2: 如果URI为文件
    # 那么跳出重写规则(如果不为文件则往下匹配)
    RewriteCond %{REQUEST_FILENAME} !-f

    # 规则3: 如果URI为目录
    # 那么跳出重写规则(如果不为目录则往下匹配)
    RewriteCond %{REQUEST_FILENAME} !-d

    # 规则4: 如果上述条件都不符合
    # 那么将URI参数传到WordPress的index.php进行处理
    RewriteRule . /index.php [L]
</IfModule>
# END WordPress
我们看一下规则4的原理:如果前面的所有规则都不匹配,那么htaccess会将URI作为参数传递到WordPress 的index.php文件中。index.php收到这个参数后,会将这个参数作为Permalink处理,具体方法是在数据库中搜索这个参数对应的Post、Category、Page等,并将对应的页面显示出来;如果数据库中没有这条记录,那么显示404错误。这个过程就是将Permalinks转换成id的过程。
再整体看一下上面的所有规则,这里使用了两个机制处理我们的URI:先是htaccess处理,如果htaccess处理不了就交给WordPress处理。404问题就出在这里,htaccess非常不负责任地把一个目录交给WordPress作为Permalink处理。如果我们访问一个子目录,如subdir1,那么应该在规则3中就已经产生匹配,并且跳出并访问该目录。但是这里匹配失败了,导致这个URI最后传给了WordPress。
找到问题就可以对症下药了:我们只要添加一些规则,保证匹配这些子目录后跳出就行了。
参考Apache的Manual(http://httpd.apache.org/docs/current/mod/mod_rewrite.html)写了几条规则测试,均未果。只好求助于万能的Google,搜了下发现遇到同样问题的还真不少,光是WordPress官网就有好几个帖子,似乎官网也没有满意的答案,只知道可能是空间商限制了。最后在WordPress Answers 找到了答案(原文链接):
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_URI} ^/subdirectoryname1/(.*)$ [OR]
    RewriteCond %{REQUEST_URI} ^/subdirectoryname2/(.*)$ [OR]
    RewriteRule ^.*$ - [L]
</IfModule>
把subdirecoryname改成你自己的子目录名称就可以了,你可以将这条规则放在WordPress Rewrite规则的前面,也可以整合进WordPress的重写规则中,方法可以参考本站的Rwrite规则(注意最后一条规则没有[OR]):
# BEGIN WordPress
# ShuYZ.com rewrite rules
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

# If visit subdirectories
# Then jump out
    RewriteCond %{REQUEST_URI} ^/apps/(.*)$ [OR]
    RewriteCond %{REQUEST_URI} ^/wap/(.*)$ [OR]
    RewriteCond %{REQUEST_URI} ^/wp-admin/(.*)$ [OR]
    RewriteCond %{REQUEST_URI} ^/wp-content/(.*)$ [OR]
    RewriteCond %{REQUEST_URI} ^/wp-includes/(.*)$
    RewriteRule ^.*$ - [L]

# Else if visit home page
# Then jump out
    RewriteRule ^index\.php$ - [L]

# Else if visit folder or file
# Then jump out
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

# Else
# The URI is permalinks, transfer it to WordPress
    RewriteRule . /index\.php [L]
</IfModule>
这样就可以完美地排除WordPress子目录了,跟404错误ByeBye吧。
需要注意的是,本方法只能解决普通目录的404错误问题,对htpasswd加密的子目录无效。加密子目录的404解决方法可参考下文。
-------------

解决htaccess加密的WordPress子目录的404错误

WordPress的确是一个折腾人的东西,刚解决子目录出现404不能访问的问题,还来不及高兴就发现使用htaccess加密的目录又不能访问了,出现了悲剧的404错误。
这的确是很奇怪的一个问题,同样的方法,可以排除WordPress的非加密子目录,却不能排除加密后的子目录。
在网上找到一种方法,虽然不明白这样做的原理,但试了下很管用。如果你也遇到WordPress的htaccess加密子目录不能访问的问题,可以试一下这个方法。
解决方法很简单:
STEP 1:   在WordPress目录的htaccess中加一条规则:
# Handle htaccess protected directories
ErrorDocument 401 /401.html
注意上面这条规则要添加到WordPress的重写规则前面。
STEP2:  在WordPress根目录下建立一个401.html文件,这个文件的内容为:
<html>
</html>
你可以用记事本建立这个文件,然后ftp到你的空间。 这样就完成了。
现在输入你的加密子目录地址看看,应该可以正常访问了。

附参考资料:
1. .htaccess and subdirectories
2. Password-protecting directories – DreamHost (DreamHost WIKI提供的解决方法)

No comments:

Post a Comment