Apache-2.4

Apache .htaccess RewriteRule 和 ErrorDocument

  • November 11, 2018

我有一個.htaccess文件:

RewriteEngine On
DirectorySlash Off

RewriteCond %{REQUEST_URI}  !(\.css|\.js|\.png|\.jpg|\.mp4|\.ttf|\.eot|\.woff)$
RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

ErrorDocument 404 /e404
ErrorDocument 403 /e404
ErrorDocument 500 /e500

還有一個 PHP 函式,用於檢查請求的 URI 是否存在。如果 URI 存在於數據庫中,則獲取內容並渲染頁面,如果不存在,則獲取 404 錯誤頁面內容並渲染頁面。(這裡一切正常)

問題是當我使用帶有文件RewriteCond部分內部副檔名的 URI 時.htaccess,例如example.com/file.css. 在這種情況下,頁面被重定向到example.com/e404 (這就是我想要的)。這裡的問題是:

我不知道如何獲取重定向到之前使用的“錯誤 URI” example.com/e404,因為當載入錯誤頁面時,我在頁面內部有一個函式可以在數據庫中插入“錯誤 URI”。

*旁白:*您發布的指令會在任何預設的 Apache 安裝上創建一個重寫循環,所以也許您有其他指令或不同的配置,您沒有在您的問題中披露?無論如何,暫時忽略這一點,因為您似乎沒有遇到這樣的問題。

我不知道如何在重定向到之前使用錯誤的 URI example.com/e404

但是你需要在“重定向”*之前獲取這些資訊嗎?*在 PHP 中,您可以簡單地檢查$_SERVER['REQUEST_URI']超全域以獲取此資訊(導致 404 的 URL)。但是,請注意,這包含斜杠前綴和查詢字元串(如果有),page否則您的 URL 參數不會包含它們。

此外,為了澄清術語,這並不是嚴格意義上的“重定向”到example.com/e404. “重定向”意味著外部 HTTP 重定向。Apache 為錯誤文件發出一個內部子請求(類似於 URL 重寫,但不完全是)。

您的程式碼的一個潛在問題是 404 響應是以一種相當迂迴的方式提供的:

  1. 如果file.css不存在,則 Apache 觸發內部子請求/e404

(這會觸發另一輪處理……) 2. 由於/e404不以所述文件副檔名之一結尾,因此將其進一步重寫為?page=e404(大概index.php?)。

由於(不必要的)第二次重寫,其他伺服器變數,例如REDIRECT_URLREDIRECT_QUERY_STRING(也傳遞給 PHP$_SERVER超全域變數)沒有按預期設置。通常,這些會被設置為“錯誤的 URI”(即觸發 404 的請求的 URL),但相反,它們包含錯誤文件本身的詳細資訊。

您應該在 1 步中執行上述操作,並避免第二次重寫。例如(假設index.php是處理請求的文件),錯誤文件應該設置為期望的最終結果:

ErrorDocument 404 /index.php?page=e404

順便說一句,您不一定需要e404在 URL 中顯式傳遞 HTTP“錯誤狀態”(即 ),因為這在 PHP 的$_SERVER['REDIRECT_STATUS']超全域中是可用的。

RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

我假設您正在重寫index.php(註冊的 DirectoryIndex)?而不是退回到讓 mod_dir 為 DirectoryIndex 發出額外的子請求,您應該明確並將您正在重寫的文件包含在替換中。例如:

RewriteRule ^(.*)$ index.php?page=$1 [QSA,L]

NC旗幟在這裡是多餘的。)

我不知道如何在重定向到之前使用錯誤的 URI example.com/e404

退後一步再次解決您的初始查詢(作為學術練習)。您可以在 Apache 2.4.13+ 上執行此操作(儘管我認為您不需要這樣做)。在 Apache 2.4.13+ 上,您可以使用 Apache 表達式創建動態 ErrorDocument。

例如,要在錯誤文件本身的 URL 中顯式傳遞導致 404 錯誤的 URL 路徑,則可以執行以下操作:

ErrorDocument 404 /index.php?page=%{escape:%{REQUEST_URI}}&error=404

然後 URL 參數page包含 URL 路徑(其中包括斜杠前綴,與您的重寫不同,它不包括它)。一個額外的errorURL 參數發送 HTTP 狀態(儘管如上所述,這不是絕對必要的)。

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