2013-11-15 103 views
1

我有這個問題我還沒有想出來,也許你可以給我一隻手。奇怪的行爲與Apache VirtualHost重寫規則和htaccess

<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前端控制器也將該請願處理爲正常請求。

在此先感謝。

+0

你爲什麼要在www和非www之間來回重定向? –

回答

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就會停止。

+0

這正是問題所在。謝謝!我想避免在我的VirtualHost配置文件中添加應用程序特定規則,但我認爲沒有其他解決方法。 –

+0

非常歡迎,很高興它爲你解決。 – anubhava

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?

+0

它將www和非www重定向到該站點的https(帶www)版本。注意VirtualHost指令中的*:80規範。我不知道是否有從HTTP_HOST中剝離「www」的方法,所以我最終做了這個破解。不這樣做導致了這種行爲: 'http://example.com - > http://www.example.com http://www.example.com - > http://www.www。 example.com' –