Windows

.htaccess mod_rewrite 重定向太多

  • April 5, 2018

為了清楚起見,這不是像這樣的重複問題,因為問題的核心是不同的。我正在嘗試做的是將嘗試使用語言程式碼(通常是enor cz)訪問站點的使用者重定向到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(臨時)重定向可以更容易地進行測試。

您的blogftp規則可以由單個指令處理,使用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]

引用自:https://serverfault.com/questions/905513