.HTACCESS 正在創建不必要的 301 重定向鏈 - 如何刪除?
我的堆棧:
- 燈
- 阿帕奇/2.4.41
背景資料:
我最近為客戶推出了一個新網站。在重新設計過程中,我們決定:
- 切換到站點範圍的 HTTPS
- 從 URL 中刪除 .php 副檔名
- 切換到 CMS
舊網址範例:
http://www.example.com/courses/acme-course.php
新網址範例:
https://www.example.com/courses/acme-course
我的問題:
當使用者導航到舊 URL 之一時,會發生不必要的額外 301 重定向。
我不明白為什麼要創建額外的 301 重定向,而不是使用單個 301 重定向將使用者直接發送到正確的目標 URL。
有趣的觀察:
當我使用帶有 HTTPS 而不是 HTTP 的舊 URL 時,不會發生不必要的額外 301 重定向。
範例:
https://www.example.com/courses/acme-course.php
_使用上面的 URL 將正確地執行一個 301 重定向到正確的目標 URL:
https://www.example.com/courses/acme-course
這是 301 重定向鏈的範例:
原始請求網址:
http://www.example.com/courses/acme-course.php
1ST 301 重定向(不必要):
從:
http://www.example.com/courses/acme-course.php
到:
https://www.example.com/index.php?url=courses/acme-course.php
2ND 301 重定向(正確的最終目標 URL):
從:
https://www.example.com/index.php?url=courses/acme-course.php
到:
https://www.example.com/courses/acme-course
我的 .htaccess 程式碼:
# (1) General Settings <IfModule mod_rewrite.c> Options +FollowSymLinks RewriteEngine On </IfModule> # (2) Force WWW <IfModule mod_rewrite.c> RewriteCond %{HTTPS} !=off RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteCond %{SERVER_ADDR} !=127.0.0.1 RewriteCond %{SERVER_ADDR} !=::1 RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] </IfModule> # (3) Force HTTPS <IfModule mod_rewrite.c> RewriteCond %{HTTPS} !=on RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L] </IfModule> # (4) URL Routing for CMS <IfModule mod_rewrite.c> RewriteCond %{HTTPS} =on RewriteRule ^ - [env=proto:https] RewriteCond %{HTTPS} !=on RewriteRule ^ - [env=proto:http] ## Check if file/directory exists RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d ## Route all other URLs to index.php/URL RewriteRule ^(.*)$ index.php?url=$1 [PT,L,QSA] </IfModule>
你有兩個主要問題……
您的指令在
.htaccess
文件中的順序錯誤。您的 HTTP 到 HTTPS 和www
規範重定向需要在將 URL 路由到 CMS 的前端控制器*之前進行。*因此不正確的外部重定向到/index.php?url=courses/acme-course.php
- 暴露您的內部 CMS URL 結構。您的指令
.php
實際上並未執行刪除操作?!.htaccess
我認為這必須由您的應用程序/CMS 邏輯完成?因此,這將始終導致第二次重定向(因為.htaccess
重定向到同一 URL 路徑上的 HTTPS)。您需要在.htaccess
文件頂部執行以下操作以刪除.php
副檔名。RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
**更新:**如果我重新排序規則/條件,我的 Options +FollowSymlinks 位置是否保持不變?
指令出現的位置並不重要。
Options
但是,將它放在頂部附近是合乎邏輯的(從可讀性的角度來看)。(Apache 指令不一定按照它們在配置文件中出現的順序執行,因為每個模組都是獨立工作的。)假設您正在對
.htaccess
文件進行手動編碼,則可以對其進行整理…
- 不需要(多個)
<IfModule mod_rewrite.c>
包裝器。mod_rewrite 是可選的嗎?您的站點是否被移植到未啟用 mod_rewrite 的多個伺服器?- 不需要多個
RewriteEngine
指令。最後一個實例實際上贏得併控制了整個文件。多個
<IfModule>
塊,RewriteEngine
是由程式碼自動編輯和/或設計為在多個伺服器上執行未經編輯的典型系統。因此,您的
.htaccess
文件應該按以下順序重寫:Options +FollowSymlinks # Enable the rewrite engine... RewriteEngine On # ---------------------------------------------------------------------- # | Forcing `https://` | # ---------------------------------------------------------------------- # Redirect to HTTPS on the "same host" (requirement for HSTS) RewriteCond %{HTTPS} !=on RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L] # ---------------------------------------------------------------------- # | Forcing `www` | # ---------------------------------------------------------------------- RewriteCond %{HTTP_HOST} !^www\. RewriteCond %{SERVER_ADDR} !=127.0.0.1 RewriteCond %{SERVER_ADDR} !=::1 RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # ---------------------------------------------------------------------- # | URL Routing for CMS | # ---------------------------------------------------------------------- # (3) RewriteCond %{HTTPS} =on RewriteRule ^ - [env=proto:https] RewriteCond %{HTTPS} !=on RewriteRule ^ - [env=proto:http] # (4) - Check if physical file exists RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # (5) - Rewrite all other URLs to index.php/URL RewriteRule (.*) index.php?url=$1 [L,QSA]
補充筆記:
PROTO
環境變數包含正在請求的任何協議。按照重定向的順序,現在始終是 HTTPS。這個變數的根本原因是,如果訪問 HTTP,CMS 可以重定向到 HTTP,如果訪問 HTTPS,則可以重定向到 HTTPS。如果您強制使用 HTTPS,那麼它實際上並不適用。(儘管您的應用程序仍可能使用此 env var。)- 您很少應該
NC
在否定條件下使用該標誌。因此,為什麼我將其從條件中刪除!^www\.
。您希望它在主機不以www.
- 全部小寫開頭時重定向。使用該NC
標誌,它將無法重定向WwW.
- 儘管無論如何這將是非常罕見的。- 我已經刪除了 www 規範重定向上對 HTTPS 的不必要檢查。
- 最後
PT
一個標誌RewriteRule
在.htaccess
. 這.htaccess
是預設行為(通過)。- 您需要在測試前清除瀏覽器記憶體,因為錯誤的 301 重定向可能已被瀏覽器記憶體。出於這個原因,使用 302(臨時)重定向進行測試是個好主意。