在 .htaccess 中處理 301 重定向和內部重寫
我想在我的網站上做三件事:
- 訪問 HTTP 版本時,將帶有 301 的使用者重定向到站點的 HTTPS 版本
- 將 301 使用者重定向到網站的“無 www”版本,當他們
www
在 url 中輸入a- 靜默(或內部)重定向
/*
到/index.php?p=*
(因為我正在使用框架)。(甚至,“視覺上”重定向/index.php?p=*
到/*
,然後在內部重定向/*
到/index.php?p=*
…)這是我目前的 .htaccess:
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] RewriteRule (.*) https://%1/$1 [R=301] RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.+) index.php?p=$1 [QSA] </IfModule>
但是,當我執行此配置時,我的 301 重定向不起作用 - 更準確地說,實際上是向客戶端發送了 301 程式碼,但沒有
Location:
發送標頭:$ curl http://mywebsite.com/path -I HTTP/1.1 301 Moved Permanently Date: Thu, 23 Apr 2020 19:03:57 GMT Server: Apache/2.4.38 (Debian) Set-Cookie: ci_session=q24j0enjrskagec2fggi256bpg5fsvs6; expires=Thu, 23-Apr-2020 20:39:57 GMT; Max-Age=7200; path=/; HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Type: text/html; charset=UTF-8
如果我嘗試將塊放在
index.php
其他兩個塊之前,HTTPS 和www
重定向工作,但是Location:
在處理頁面時標題有一個奇怪的行為:λ curl http://mywebsite.com/fr/salon -I HTTP/1.1 301 Moved Permanently Date: Thu, 23 Apr 2020 19:09:03 GMT Server: Apache/2.4.38 (Debian) Location: https://mywebsite.com/fr/salon?p=fr/salon Content-Type: text/html; charset=iso-8859-1
(您還可以看到字元集發生了變化,出於某種奇怪的原因)
我必須對我的規則進行哪些更改才能使我的三個重定向起作用?
謝謝!
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] RewriteRule (.*) https://%1/$1 [R=301] RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301]
您在兩個重定向中都缺少
L
(last
) 標誌。如果沒有L
標誌,處理將繼續並被隨後的內部重寫擷取。例如:
RewriteRule (.*) https://%1/$1 [R=301,L]
**更新:**您也應該在以後的重寫中嚴格包含該
L
標誌。雖然如果這是最後一次RewriteRule
,那麼它並不重要。但是,如果您稍後添加更多規則,那麼它可能很重要。甚至,將“視覺”重定向
/index.php?p=*
到/*
僅當您更改現有 URL 結構(其中舊
index.php?p=
URL 由搜尋引擎索引或由第三方連結到)時,才嚴格要求此部分。這裡的重點是通過防止重寫的 URL 被重定向來避免潛在的重定向循環。我們可以通過檢查
REDIRECT_STATUS
環境變數來做到這一點(初始請求為空並設置為“200”,如第一次成功重寫後的 200 OK HTTP 狀態)。例如,在您現有的重定向之前,在
RewriteBase
指令之後,您可以立即執行以下操作以從外部重定向/index.php?p=*
到/*
:RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{QUERY_STRING} ^p=([^&]*) RewriteRule ^index\.php$ https://example.com/%1 [QSD,R=302,L]
(
QSD
查詢字元串丟棄)標誌(Apache 2.4+)是必要的,以便p=*
從請求中刪除查詢字元串(即 URL 參數)。這確實假設您沒有其他需要傳遞的 URL 參數 - 它們都被丟棄。這還假設
p
URL 參數始終出現在查詢字元串的開頭(根據您的重寫)。通過在替換字元串中包含絕對 URL,我們避免了與請求 HTTP 或 www 子域相關的任何二級重定向。
請注意,這目前是 302(臨時)重定向。最好先使用 302 進行測試,然後再更改為 301(永久)重定向以避免潛在的記憶體問題。