Apache VirtualHost重写规则和htaccess的奇怪行为

时间:2013-11-15 17:57:57

标签: regex apache .htaccess symfony mod-rewrite

我有这个问题我还没弄明白,也许你可以帮我一把。

<VirtualHost *:80>

    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot "/var/www/example.com/current/web/"

    RewriteEngine On

    RewriteLog "/var/log/apache2/rewrite.log"
    RewriteLogLevel 3

    RewriteCond %{REQUEST_URI} !^/api/special/url/token
    RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
    RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,QSA]

    RewriteCond %{REQUEST_URI} !^/api/special/url/token
    RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,QSA]

</VirtualHost>

这是我的VirtualHost配置,我需要将所有内容重定向到HTTPS协议,但一个特定的URL除外。

此VirtualHost规则正常运行。问题是,当进入带有.htaccess文件(来自Symfony2标准版)的DocumentRoot时,会产生一种奇怪的行为。这是.htaccess文件:

DirectoryIndex app.php

RewriteEngine On

RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]

RewriteRule .? %{ENV:BASE}/app.php [L]

这是RewriteLog日志:

[example.com/sid#b740c280][rid#b62df058/initial] (2) init rewrite engine with requested uri /api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) applying pattern '(.*)' to uri '/api/special/url/token'
[example.com/sid#b740c280][rid#b62df058/initial] (3) applying pattern '(.*)' to uri '/api/special/url/token'
[example.com/sid#b740c280][rid#b62df058/initial] (1) pass through /api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] add path info postfix: /var/www/example.com/current/web/api -> /var/www/example.com/current/web/api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] strip per-dir prefix: /var/www/example.com/current/web/api/special/url/token -> api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] applying pattern '^(.*)' to uri 'api/special/url/token'
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] add path info postfix: /var/www/example.com/current/web/api -> /var/www/example.com/current/web/api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] strip per-dir prefix: /var/www/example.com/current/web/api/special/url/token -> api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] applying pattern '.?' to uri 'api/special/url/token'
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] add path info postfix: /var/www/example.com/current/web/api -> /var/www/example.com/current/web/api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] strip per-dir prefix: /var/www/example.com/current/web/api/special/url/token -> api/special/url/token
[example.com/sid#b740c280][rid#b62df058/initial] (3) [perdir /var/www/example.com/current/web/] applying pattern '.?' to uri 'api/special/url/token'
[example.com/sid#b740c280][rid#b62df058/initial] (2) [perdir /var/www/example.com/current/web/] rewrite 'api/special/url/token' -> '/app.php'
[example.com/sid#b740c280][rid#b62df058/initial] (1) [perdir /var/www/example.com/current/web/] internal redirect with /app.php [INTERNAL REDIRECT]
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (2) init rewrite engine with requested uri /app.php
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (3) applying pattern '(.*)' to uri '/app.php'
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (2) rewrite '/app.php' -> 'https://www.example.com/app.php'
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (2) explicitly forcing redirect with https://www.example.com/app.php
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (1) escaping https://www.example.com/app.php for redirect
[example.com/sid#b740c280][rid#b6291310/initial/redir#1] (1) redirect to https://www.example.com/app.php [REDIRECT/301]

预期的行为是,当匹配此特定URL时,它不会重定向到HTTPS URL,并且Symfony2前端控制器也会将请求作为正常URL处理。

提前致谢。

2 个答案:

答案 0 :(得分:2)

我认为问题是第一个配置是在虚拟主机中,第二个是在文件夹中的.htaccess中,htaccess有优先级,让我们考虑一下这个结构

├──folder1
│  ├── .htaccess1
│  ├── folder2
│  │   ├── .htaccess2
│  │   ├── folder3
│  │   │   ├──.htaccess 3

.htaccess1内的规则将被.htaccess2覆盖,并且.htaccess3内的选项都会覆盖这两个规则,最后一个优先级是virtualhost内的选项自

所以我假设只有2个选项,要么将重写从virtualhost级别移动到symfony .htaccess文件中,要么尝试通过.htaccess中的条件转义它们。等待他们冒泡回到virtualhost以在那里应用规则。

我认为这样的组合.htaccess可以解决问题

DirectoryIndex app.php

RewriteEngine On

# https redirections
RewriteCond %{REQUEST_URI} !^/api/special/url/token
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,QSA]

RewriteCond %{REQUEST_URI} !^/api/special/url/token
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,QSA]

# symfony2 rewriting
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]

RewriteRule .? %{ENV:BASE}/app.php [L]

虽然我收到了评论,但我真的不明白你要做什么,你在www和非www之间来回重定向?

答案 1 :(得分:1)

问题是Symhony的前端控制器/app.php也被重定向到HTTPS,因为RewriteCond %{REQUEST_URI} !^/api/special/url/token仍然成立。将VirtualHost规则替换为:

RewriteCond %{REQUEST_URI} !^/(api/special/url/token|app\.php)
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

RewriteCond %{REQUEST_URI} !^/(api/special/url/token|app\.php)
RewriteCond %{HTTP_HOST} ^www\..+$ [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

进行此更改后,请不要忘记重新启动Apache服务器。完成后,将停止对HTTPS的不需要的重定向。