我寫了一個Web應用程序,我運行在一個專用的服務器上託管Web應用程序。此Web應用程序的實例可在不同的域中使用,並且每個域都有自己的Web應用程序文件副本,允許根據需要進行定製。如何在使用通配符的Directory指令中使用apache2 mod_rewrite?
我在Debian Squeeze下運行Apache/2.2.16。
我在VirtualHost指令下執行所有配置,不使用.htaccess文件。
爲了簡化apache的配置,我想維持像這樣的單個目錄指令:
<Directory "/srv/www/*/public/">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>
然而,重寫規則產生錯誤的結果,因爲在使用通配符指南值,它未能剝離每個目錄前綴。這裏是重寫日誌的輸出:
[rid#b9832078/initial] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/login'
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9832078/initial] (2) [perdir /srv/www/*/public/] rewrite '/srv/www/domain1/public/login' -> '/index.php?q=/srv/www/domain1/public/login'
[rid#b9832078/initial] (3) split uri=/index.php?q=/srv/www/domain1/public/login -> uri=/index.php, args=q=/srv/www/domain1/public/login
[rid#b9832078/initial] (1) [perdir /srv/www/*/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b9847440/initial/redir#1] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/index.php'
[rid#b9847440/initial/redir#1] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b9847440/initial/redir#1] (1) [perdir /srv/www/*/public/] pass through /srv/www/domain1/public/index.php
的問題是,在重寫規則「URI」是文件系統路徑,而不是URL路徑,這導致查詢字符串是不正確的:Q =/SRV/WWW /域1 /公/登錄
顯式指定的目錄路徑就像這樣:
<Directory "/srv/www/domain1/public/">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>
工作得很好,在這裏被改寫日誌顯示正確的行爲(不同之處是新的輸出冷杉牛逼附加線提供正確的輸入產生正確的查詢字符串重寫的休息:Q =登錄):
[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/login -> login
[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'login'
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9868048/initial] (2) [perdir /srv/www/domain1/public/] rewrite 'login' -> '/index.php?q=login'
[rid#b9868048/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b9868048/initial] (1) [perdir /srv/www/domain1/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/index.php -> index.php
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'index.php'
[rid#b987d5f8/initial/redir#1] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b987d5f8/initial/redir#1] (1) [perdir /srv/www/domain1/public/] pass through /srv/www/domain1/public/index.php
我希望我遇到與Apache的錯誤,但如果ISN這種情況,我做錯了什麼?
雖然我很欣賞將方法改爲另一個可行的解決方案的輸入,但我會接受一個答案,以我採取的方法解決它(例如,不使用.htaccess),除非可以顯示此方法不可解。
因此,在通配符目錄中使用時,是否有必須更改爲RewriteCond/Rules?
好奇的一面注意事項:爲了進一步簡化,我使用了一個使用VirtualDocumentRoot的單一VirtualHost - 但這與這個問題在使用'DocumentRoot'並在單個域下測試時複製無關。
編輯
好吧,這基於regilero的答案,在這裏我已經重新出現是什麼 - 移動重寫,按原樣出目錄的結果在輕微的首要問題查詢字符串從「登錄」更改爲「/登錄」,這通過修改RewriteRule爲:RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]
修復了我以前的「莫名其妙的失敗」評論。
在此之後,所有的靜態文件加載失敗,這裏是顯示這個問題重寫日誌:
[rid#b7bc7fa0/initial] (2) init rewrite engine with requested uri /login
[rid#b7bc7fa0/initial] (3) applying pattern '^/(.+)$' to uri '/login'
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-f' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-d' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b7bc7fa0/initial] (2) rewrite '/login' -> '/index.php?q=login'
[rid#b7bc7fa0/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b7bc7fa0/initial] (2) local path result: /index.php
[rid#b7bc7fa0/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7bc7fa0/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]
[rid#b7be6b80/initial] (2) init rewrite engine with requested uri /static/css/common.css
[rid#b7be6b80/initial] (3) applying pattern '^/(.+)$' to uri '/static/css/common.css'
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-f' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-d' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/favicon.ico' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/robots.txt' => matched
[rid#b7be6b80/initial] (2) rewrite '/static/css/common.css' -> '/index.php?q=static/css/common.css'
[rid#b7be6b80/initial] (3) split uri=/index.php?q=static/css/common.css -> uri=/index.php, args=q=static/css/common.css
[rid#b7be6b80/initial] (2) local path result: /index.php
[rid#b7be6b80/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7be6b80/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]
但是就像我在我的評論說regilero的回答,這是由前綴解決RewriteCond指令帶有%{DOCUMENT_ROOT}的TestString。但是,使用%{DOCUMENT_ROOT}在使用VirtualDocumentRoot時不起作用。
對於我而言,%{DOCUMENT_ROOT}前綴應該是必需的。
編輯
REQUEST_FILENAME
完整的本地文件系統中的文件路徑或腳本匹配 請求時,如果這已經由服務器在 REQUEST_FILENAME被引用的時間來決定。否則,如在虛擬主機上下文中使用 時,與REQUEST_URI的值相同。
它解釋了需要DOCUMENT_ROOT前綴。
我已經更新了重寫規則這樣:
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{REQUEST_URI} !^/static/
RewriteRule ^/(.+)$ /index.php?q=$1 [PT,L,QSA]
哪些工作正常(注:PT標誌必須避免過早使用VirutalDocumentRoot當翻譯URL路徑文件系統路徑)。這裏行爲的主要變化是RewriteCond對於進入應用程序的所有入口點都是必需的 - 類似於/ static行。
編輯
這是任何目錄指令超出了我的虛擬主機重寫指令的最終化身:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/static/
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^/(.+)$ /index.php?q=$1 [NS,PT,L,QSA]
RewriteRule ^/$ /index.php [NS,PT,L,QSA]
我已經添加了NS
標誌,以避免額外的內部評估,並添加第二個RewriteRule
指令傾向於使用mod_dir和DirectoryIndex
。我的應用程序預計根URL沒有q =參數,否則如果應用程序被更新爲接受根URL的空q=
參數,則單個RewriteRule
的RewriteRule ^/(.*)$ /index.php?q=$1 [NS,PT,L,QSA]
就足夠了。我可能會在未來做到這一點。
它沒有,我以前試過,它需要在RewriteCond的前綴%{DOCUMENT_ROOT} - 但即使如此,它莫名其妙地失敗。我將很快重新運行該設置以提供重寫日誌輸出。另外,使用%{DOCUMENT_ROOT}在Apache2.2中無法使用VirtualDocumentRoot - 雖然最近幾天前已經修復了Apache2。3 – chris 2011-06-15 16:21:53
因此,您可以嘗試使用mod_macro來代替VirtualDocumentRoot方法,但在mod_vhost_alias中引入的所有錯誤都不存在於由mod_macro定義的虛擬主機(但您需要每個新用戶的一行conf)。 – regilero 2011-06-15 16:42:07
我已經更新了我的問題,並在Directory指令之外移動了重寫指令的結果。 – chris 2011-06-15 16:53:02