Dot-Htaccess

.HTACCESS 正在創建不必要的 301 重定向鏈 - 如何刪除?

  • January 11, 2020

我的堆棧:

  • 阿帕奇/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>

你有兩個主要問題……

  1. 您的指令在.htaccess文件中的順序錯誤。您的 HTTP 到 HTTPS 和www規範重定向需要在將 URL 路由到 CMS 的前端控制器*之前進行。*因此不正確的外部重定向到/index.php?url=courses/acme-course.php- 暴露您的內部 CMS URL 結構。

  2. 您的指令.php實際上並未執行刪除操作?!.htaccess我認為這必須由您的應用程序/CMS 邏輯完成?因此,這將始終導致第二次重定向(因為.htaccess重定向到同一 URL 路徑上的 HTTPS)。您需要在.htaccess文件頂部執行以下操作以刪除.php副檔名。

RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]

**更新:**如果我重新排序規則/條件,我的 Options +FollowSymlinks 位置是否保持不變?

指令出現的位置並不重要。Options但是,將它放在頂部附近是合乎邏輯的(從可讀性的角度來看)。(Apache 指令不一定按照它們在配置文件中出現的順序執行,因為每個模組都是獨立工作的。)

假設您正在對.htaccess文件進行手動編碼,則可以對其進行整理…

  1. 不需要(多個)<IfModule mod_rewrite.c>包裝器。mod_rewrite 是可選的嗎?您的站點是否被移植到未啟用 mod_rewrite 的多個伺服器?
  2. 不需要多個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(臨時)重定向進行測試是個好主意。

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