Mod-Rewrite

在 .htaccess 中處理 301 重定向和內部重寫

  • April 28, 2020

我想在我的網站上做三件事:

  • 訪問 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 參數 - 它們都被丟棄。

這還假設pURL 參數始終出現在查詢字元串的開頭(根據您的重寫)。

通過在替換字元串中包含絕對 URL,我們避免了與請求 HTTP 或 www 子域相關的任何二級重定向。

請注意,這目前是 302(臨時)重定向。最好先使用 302 進行測試,然後再更改為 301(永久)重定向以避免潛在的記憶體問題。

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