.htaccess mod_rewrite 重定向太多
為了清楚起見,這不是像這樣的重複問題,因為問題的核心是不同的。我正在嘗試做的是將嘗試使用語言程式碼(通常是
en
orcz
)訪問站點的使用者重定向到index.php
設置了語言變數的使用者。該站點本身只能辨識英語和捷克語設置,其他所有設置都根據訪問者的 IP 地理位置進行重定向(使用外部線上 JSON API)。但問題是,該瀏覽器不斷地重定向,並返回一個錯誤,即發生了太多重定向。怎麼了?試圖尋找錯誤,但看不到任何錯誤。這是完整的
.htaccess
文件:Options -Indexes RewriteEngine on RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1 RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301] RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]
此外,如果使用者寫入
index.php?lang=$1
,我需要將他重定向到漂亮的 URL 變體。我在網上搜尋過,但對我來說似乎太複雜了:(在準備線上部署之前,我正在我的 Windows 機器上的 WAMP 伺服器中測試站點。
您實際上沒有說明您請求觸發重定向循環的 URL?
但是,從您發布的指令來看,似乎任何形式的請求
/blog<anything>
都會/ftp<anything>
導致重定向循環。RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301] RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]
Apache mod_rewrite 不支持
RewriteRule
替換中的協議相對 URL - 它們被簡單地視為根相對(即相對於文件根的 URL 路徑)。您大概會在瀏覽器的地址欄中看到此重定向循環的結果嗎?它會是這樣的:
- 初始請求:
http://example.com/blog/xyz
- 重定向到
http://example.com//blog.czghost.czlh/xyz
- 重定向到
http://example.com//blog.czghost.czlh/.czghost.czlh/xyz
- 重定向到
http://example.com//blog.czghost.czlh/.czghost.czlh/.czghost.czlh/xyz
- 等等
您需要包含協議。例如:
RewriteRule ^blog/?(.*)$ https://blog.czghost.czlh/$1 [R=301,L]
我還包括了
L
(last
) 標誌,因為您希望重定向立即觸發,而不是冒被進一步重寫的風險。這真的應該在內部重寫(重寫為index.php
)之前發生。您需要確保已清除瀏覽器記憶體,因為錯誤的 301(永久)重定向將被瀏覽器記憶體。出於這個原因,使用 302(臨時)重定向可以更容易地進行測試。
您的
blog
和ftp
規則可以由單個指令處理,使用alternation。例如:RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]
RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1
您在模式中沒有擷取組(即帶括號的子
RewriteRule
模式) ,因此$1
反向引用將始終為空。這應該重寫為:RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]
同樣,我已經包含了
L
標誌,以防止進一步重寫。請注意,這需要在 URL 路徑的末尾有一個斜杠後綴。因此,只有表單/blog/en/
(帶有斜杠後綴)的 URL 會被成功重寫(儘管這可能是無關的)。所以,總而言之,這應該被重寫為:
RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L] RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]
此外,如果使用者寫入
index.php?lang=$1
,我需要將他重定向到漂亮的 URL 變體。您可以在上述指令之前通過額外的重定向來做到這一點。例如:
RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$ RewriteRule ^(index\.php)?$ /%1/? [R=301,L]
您需要使用
RewriteCond
指令根據QUERY_STRING
伺服器變數檢查查詢字元串(這不能在RewriteRule
指令中完成)。前面對REDIRECT_STATUS
環境變數的檢查是為了確保我們只處理初始請求,而不是由後面將 URL 重寫為/index.php?lang=xyz
. env var在REDIRECT_STATUS
初始請求中為空,但在第一次成功rewrite後設置為“200”(如 200 OK - HTTP 狀態) 。這將匹配
index.php
或空 URL 路徑(例如/?lang=xyz
)。%1
是對最後一個匹配的CondPattern的反向引用(與之相反的$N
是對RewriteRule
模式的反向引用)。為了從重定向的 URL 中刪除查詢字元串,替換末尾的 是必要的(或者,您可以在 Apache 2.4+ 上使用該標誌?
)。RewriteRule
QSD
同樣,最好先使用不會被瀏覽器記憶體的 302(臨時)重定向進行測試。
*(來自評論:)*唯一正常工作的是
/ftp/
重定向。/blog/
重定向在空白頁面中保持不變的 URL您應該確保文件系統上沒有同名的物理目錄,即。
/blog
. 並且這個子目錄沒有.htaccess
可以覆蓋它的附加文件。另外,請確保沒有共享相同 basename的文件blog
。例如。blog.html
等等blog.php
。如果有,那麼您需要確保未啟用 MultiViews(mod_negotiation 的一部分)。IE。Options -Indexes -MultiViews
. 如果啟用了 MultiViews,則 Apache 將/blog.php
在 mod_rewrite 能夠重寫 URL 之前(例如)發出內部子請求。概括
Options -Indexes -MultiViews RewriteEngine on # Redirect direct requests for "index.php?lang=xyz" to "/xyz/" RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$ RewriteRule ^(index\.php)?$ /%1/? [R=301,L] # Redirect "blog" or "ftp/<anything>" to subdomain RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L] # Internally rewrite "/xyz/" to "/index.php?lang=xyz" RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]