為什麼 .htaccess 中的重定向不起作用?

為什麼 .htaccess 中的重定向不起作用?

我有一個 WordPress 網站。我想將 .php 網址重新導向到不含 .php 字尾的網址。 .htaccess 如下:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On


RewriteRule ^(.*)\.php$ "$1" [R=301,L,NC]


RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

但當我訪問時https://www.example.com/somepage.php,頁面無法顯示。瀏覽器中顯示以下錯誤:

The page isn’t redirecting properly

    An error occurred during a connection to www.example.com.
    
        This problem can sometimes be caused by disabling or refusing to accept cookies.

網址列中的 url 變成 https://www.example.com/index

如果我將重寫規則更改為:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On


RewriteRule ^(.*)\.html$ "$1" [R=301,L,NC]


RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

並參觀https://www.example.com/somepage.html,它已成功重定向到https://www.example.com/somepage且網頁顯示正常。為什麼?

答案1

因為,由於重定向是無條件的,你最終會再次重定向URL 已重寫為index.php(WordPress 前端控制器)。

當您請求時/somepage.php

  1. 您將被重新導向到/somepage(根據第一條規則)。重定向回應被傳送回客戶端。
  2. 在第二個請求時,由最後一條規則/somepage在內部重寫。/index.php然後重寫引擎重新啟動(在目錄情境)...
  3. /index.php被重定向到/index(根據第一條規則)。重定向回應被傳送回客戶端。
  4. 在第三個請求上,由最後一次重寫/index在內部重寫。/index.php然後重寫引擎重新啟動.....
  5. 轉到 3(陷入無限重定向循環)。

在一個目錄上下文(如.htaccess)重寫引擎並不簡單地透過腳本進行單次傳遞。它會循環直到 URL 不變地通過。 (除非您END在 Apache 2.4 上使用該標誌,否則會發生外部 3xx 重定向。)

變更為刪除.html工作正常,因為您正在重寫/index.php,它不以 結尾.html,因此重定向指令(刪除.html)不符。

要解決此問題,您需要避免重定向重寫的請求。您可以透過以下任一方式執行此操作:

  • END在最後一次重寫時使用標誌(Apache 2.4+),而不是L防止重寫引擎的任何進一步循環。儘管您應該避免更改預設的 WordPress 指令(請參閱下文),因此這可能不是首選選項。這在 Apache 2.2 上也不起作用。

  • 或者,檢查伺服器變數.php的副檔名THE_REQUEST(其中包含 HTTP 請求標頭的初始行,並且在重寫請求時不會變更)。例如:

    # Remove ".php" extension on "direct" (not rewritten) requests only
    RewriteCond %{THE_REQUEST} [A-Z]{3,7}\s/[^?]+\.php(?:\?|\s|$) [NC]
    RewriteRule (.+)\.php$ /$1 [R=301,L,NC]
    
  • 或者,檢查REDIRECT_STATUS環境變量,該變量在初始請求時為空,並在第一次成功重寫時設置為 200(如 200 OK HTTP 狀態)(這比上面更複雜的正則表達式更簡單)。例如:

    # Remove ".php" extension on "direct" (not rewritten) requests only
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.+)\.php$ /$1 [R=301,L,NC]
    

但是,您不應該編輯該部分內的程式碼# BEGIN WordPress,因為 WordPress 本身會嘗試維護此程式碼,並且稍後可能會覆寫此程式碼。這條規則需要取消評論# BEGIN WordPress標記。您無需重複RewriteEngine On文件中稍後出現的指令(在 WordPress 部分)。

在測試之前,您需要清除瀏覽器緩存,因為錯誤的(永久)重定向可能已被瀏覽器快取。首先使用 301(臨時)重定向進行測試以避免快取問題。

但是,僅此一點並不允許您存取.php沒有副檔名的檔案.php。由於無副檔名 URL 需要在內部重寫回檔案.php

相關內容