我运行 8-10 个基于 EC2 的 Web 服务器,因此我的经验非常丰富,但仅限于 CentOS;特别是 Amazon 的发行版。我使用 yum 安装 Apache,因此获取 Amazon 的默认 Apache 编译。
我想使用 mod_rewrite 实现从非 www(裸/根)域到 www.domain.com 的规范重定向以进行 SEO,但我的 .htaccess 文件一直被忽略。
我的故障排除步骤(如下所述)使我相信这是亚马逊构建的 Apache 所特有的问题。
测试用例
- 启动 EC2 实例,例如
Amazon Linux AMI 2013.03.1
- SSH 到服务器
运行以下命令:
$ sudo yum install httpd
$ sudo apachectl start
$ sudo vi /etc/httpd/conf/httpd.conf
$ sudo apachectl restart
$ sudo vi /var/www/html/.htaccess
在 httpd.conf 中,我在 DOCROOT 部分/范围中进行了以下内容更改:
AllowOverride All
在.htaccess中,添加:
(编辑,我RewriteEngine On
后来添加)
RewriteCond %{HTTP_HOST} ^domain\.com$ [NC]
RewriteRule ^/(.*) http://www.domain.com/$1 [R=301,L]
.htaccess 上的权限是正确的,AFAI 可以判断:
$ ls -al /var/www/html/.htaccess -rwxrwxr-x 1 git apache 142 Jun 18 22:58 /var/www/html/.htaccess
其他信息:
$ httpd -v
Server version: Apache/2.2.24 (Unix)
Server built: May 20 2013 21:12:45
$ httpd -M
Loaded Modules:
core_module (static)
...
rewrite_module (shared)
...
version_module (shared)
Syntax OK
预期行为
$ curl -I domain.com
HTTP/1.1 301 Moved Permanently
Date: Wed, 19 Jun 2013 12:36:22 GMT
Server: Apache/2.2.24 (Amazon)
Location: http://www.domain.com/
Connection: close
Content-Type: text/html; charset=UTF-8
实际行为
$ curl -I domain.com
HTTP/1.1 200 OK
Date: Wed, 19 Jun 2013 12:34:10 GMT
Server: Apache/2.2.24 (Amazon)
Connection: close
Content-Type: text/html; charset=UTF-8
故障排除步骤
在.htaccess中,添加:
BLAH BLAH BLAH ERROR
RewriteCond %{HTTP_HOST} ^domain\.com$ [NC]
RewriteRule ^/(.*) http://www.domain.com/$1 [R=301,L]
我的服务器抛出了错误 500,所以我知道 .htaccess 文件已被处理。
正如预期的那样,它创建了一个错误日志条目:
[Wed Jun 19 02:24:19 2013] [alert] [client XXX.XXX.XXX.XXX] /var/www/html/.htaccess: Invalid command 'BLAH BLAH BLAH ERROR', perhaps misspelled or defined by a module not included in the server configuration
由于我在服务器上拥有 root 访问权限,因此我尝试将重写规则直接移至 httpd.conf 文件。这有效。这告诉我们有几件重要的事情正在发挥作用。
$ curl -I domain.com
HTTP/1.1 301 Moved Permanently
Date: Wed, 19 Jun 2013 12:36:22 GMT
Server: Apache/2.2.24 (Amazon)
Location: http://www.domain.com/
Connection: close
Content-Type: text/html; charset=UTF-8
然而,它无法在 .htaccess 文件中工作,这让我很困扰。而且我还有其他用例需要它在 .htaccess 中工作(例如具有命名虚拟主机的 EC2 实例)。
预先感谢您的帮助。
答案1
您可以将 RewriteRules 放在服务器配置中,也可以放在 .htaccess 中。但是,它们之间存在差异,这意味着在服务器配置中有效的规则不一定在 .htaccess 上下文中有效,反之亦然。.htaccess 文件(和目录上下文)中的 RewriteRules 与相对 URL 匹配,因此以 / 开头的规则永远不会被匹配。启用 rewritelog 后您就会看到结果。
因此假设 docroot 是 /var/www 并且你请求http://myserver.com/foo/bar.html
服务器配置中的重写规则将与 /foo/bar.html 进行匹配
上下文中的重写规则或 /var/www/foo 中的 .htaccess 文件中的重写规则将仅与 bar.html 匹配。因此,如果它以 / 开头,则永远不会匹配。
意识到这一点很重要,这也是我通常认为在 .htaccess 文件中使用重写规则是个坏主意的原因之一。我通常强烈建议不要在 .htaccess 文件中使用重写规则(如果可以避免的话)(并且您可以访问 httpd.conf,因此您可以这样做)。.htaccess 文件中的重写规则通常会导致难以诊断的行为,并且会严重影响性能。
另请参阅 apache 文档: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule
“在目录和 htaccess 上下文中,模式最初将与文件系统路径进行匹配,然后删除引导服务器到当前 RewriteRule 的前缀(例如“app1/index.html”或“index.html”,具体取决于指令的定义位置)。”