如何管理錯誤回報¶
當您運行公開網站時,應該始終關閉 DEBUG
設定。這樣會使您的伺服器運行速度更快,並且還可以防止惡意使用者看到錯誤頁面中可能洩露的應用程式詳細資訊。
但是,將 DEBUG
設定為 False
表示您永遠不會看到網站產生的錯誤 - 所有人將會看到您的公開錯誤頁面。您需要追蹤已部署網站中發生的錯誤,因此可以將 Django 配置為建立包含這些錯誤詳細資訊的報告。
電子郵件報告¶
伺服器錯誤¶
當 DEBUG
為 False
時,每當您的程式碼引發未處理的例外狀況並導致內部伺服器錯誤時(嚴格來說,對於任何 HTTP 狀態碼為 500 或更高的回應),Django 都會向 ADMINS
設定中列出的使用者發送電子郵件。這會讓管理員立即收到任何錯誤的通知。ADMINS
將會收到錯誤描述、完整的 Python 回溯以及導致錯誤的 HTTP 請求的詳細資訊。
注意
為了傳送電子郵件,Django 需要一些設定來告訴它如何連線到您的郵件伺服器。至少,您需要指定 EMAIL_HOST
,並且可能需要指定 EMAIL_HOST_USER
和 EMAIL_HOST_PASSWORD
,不過,根據您的郵件伺服器的設定,可能也需要其他設定。請參閱 Django 設定文件 以取得完整的電子郵件相關設定清單。
預設情況下,Django 將會從 root@localhost 發送電子郵件。但是,某些郵件提供者會拒絕來自此地址的所有電子郵件。若要使用不同的寄件者地址,請修改 SERVER_EMAIL
設定。
若要啟用此行為,請將收件者的電子郵件地址放入 ADMINS
設定中。
另請參閱
伺服器錯誤電子郵件是使用記錄框架傳送的,因此您可以透過自訂您的記錄配置來自訂此行為。
404 錯誤¶
Django 也可以設定為發送關於連結損壞的錯誤(404「找不到頁面」錯誤)的電子郵件。在下列情況下,Django 會發送關於 404 錯誤的電子郵件:
DEBUG
為False
;您的
MIDDLEWARE
設定包含django.middleware.common.BrokenLinkEmailsMiddleware
。
如果符合這些條件,每當您的程式碼引發 404 錯誤且請求具有 referer 時,Django 都會向 MANAGERS
設定中列出的使用者發送電子郵件。它不會發送沒有 referer 的 404 錯誤的電子郵件 – 這些通常是人們輸入損壞的 URL 或損壞的網路機器人。當 referer 等於請求的 URL 時,它也會忽略 404 錯誤,因為這種行為也是來自損壞的網路機器人。
注意
BrokenLinkEmailsMiddleware
必須出現在其他攔截 404 錯誤的中介軟體之前,例如 LocaleMiddleware
或 FlatpageFallbackMiddleware
。請將它放在您的 MIDDLEWARE
設定的頂部。
您可以透過調整 IGNORABLE_404_URLS
設定,來告訴 Django 停止報告特定的 404 錯誤。它應該是一個已編譯的正規表示式物件的清單。例如
import re
IGNORABLE_404_URLS = [
re.compile(r"\.(php|cgi)$"),
re.compile(r"^/phpmyadmin/"),
]
在此範例中,不會報告任何以 .php
或 .cgi
結尾的 URL 的 404 錯誤。也不會報告任何以 /phpmyadmin/
開頭的 URL。
以下範例顯示如何排除瀏覽器和網路爬蟲經常請求的一些傳統 URL
import re
IGNORABLE_404_URLS = [
re.compile(r"^/apple-touch-icon.*\.png$"),
re.compile(r"^/favicon\.ico$"),
re.compile(r"^/robots\.txt$"),
]
(請注意,這些是正規表示式,因此我們在句點前加上反斜線來跳脫它們。)
如果您想要進一步自訂 django.middleware.common.BrokenLinkEmailsMiddleware
的行為(例如,忽略來自網路爬蟲的請求),您應該將其子類化並覆寫其方法。
另請參閱
404 錯誤是使用記錄框架記錄的。預設情況下,這些記錄會被忽略,但是您可以透過編寫處理常式並適當地設定記錄,將它們用於錯誤回報。
篩選錯誤報告¶
警告
篩選敏感資料是一個難題,幾乎不可能保證敏感資料不會洩露到錯誤報告中。因此,錯誤報告應該僅供信任的團隊成員使用,並且您應該避免透過網際網路(例如透過電子郵件)以未加密的方式傳輸錯誤報告。
篩選敏感資訊¶
錯誤報告對於偵錯錯誤非常有幫助,因此記錄盡可能多關於這些錯誤的相關資訊通常很有用。例如,預設情況下,Django 會記錄引發的例外狀況的完整回溯、每個回溯框架的局部變數,以及 HttpRequest
的 屬性。
但是,有時候某些類型的資訊可能太敏感,因此不適合追蹤,例如使用者的密碼或信用卡號碼。因此,除了篩選掉 DEBUG
文件中所述的似乎很敏感的設定之外,Django 還提供了一組函式裝飾器,以協助您控制在生產環境中(也就是 DEBUG
設定為 False
的環境)應該從錯誤報告中篩選掉哪些資訊:sensitive_variables()
和 sensitive_post_parameters()
。
- sensitive_variables(*variables)[原始碼]¶
如果你的程式碼中的函式(無論是視圖或任何常規回呼函式)使用可能包含敏感資訊的區域變數,你可以使用
sensitive_variables
裝飾器來防止這些變數的值被包含在錯誤報告中。from django.views.decorators.debug import sensitive_variables @sensitive_variables("user", "pw", "cc") def process_info(user): pw = user.pass_word cc = user.credit_card_number name = user.name ...
在上面的範例中,
user
、pw
和cc
變數的值將會被隱藏,並在錯誤報告中以星號(**********
)取代,而name
變數的值則會被公開。若要系統性地隱藏函式的所有區域變數,使其不顯示在錯誤日誌中,請不要提供任何參數給
sensitive_variables
裝飾器。@sensitive_variables() def my_function(): ...
當使用多個裝飾器時
如果你想隱藏的變數同時也是函式的參數(例如,以下範例中的 '
user
'),且被裝飾的函式有多個裝飾器,請務必將@sensitive_variables
放在裝飾器鏈的最頂端。這樣它也會隱藏在其他裝飾器中傳遞的函式參數。@sensitive_variables("user", "pw", "cc") @some_decorator @another_decorator def process_info(user): ...
在 Django 5.0 中變更新增了對包裝
async
函式的支援。
- sensitive_post_parameters(*parameters)[原始碼]¶
如果你的某個視圖接收到一個
HttpRequest
物件,其帶有POST 參數
,這些參數可能包含敏感資訊,你可以使用sensitive_post_parameters
裝飾器來防止這些參數的值被包含在錯誤報告中。from django.views.decorators.debug import sensitive_post_parameters @sensitive_post_parameters("pass_word", "credit_card_number") def record_user_profile(request): UserProfile.create( user=request.user, password=request.POST["pass_word"], credit_card=request.POST["credit_card_number"], name=request.POST["name"], ) ...
在上面的範例中,
pass_word
和credit_card_number
POST 參數的值將會被隱藏,並在錯誤報告中請求的表示形式中以星號(**********
)取代,而name
參數的值則會被公開。若要系統性地隱藏錯誤報告中請求的所有 POST 參數,請不要提供任何參數給
sensitive_post_parameters
裝飾器。@sensitive_post_parameters() def my_view(request): ...
對於某些
django.contrib.auth.views
視圖(login
、password_reset_confirm
、password_change
,以及auth
管理介面中的add_view
和user_change_password
),所有 POST 參數都會被系統性地從錯誤報告中過濾掉,以防止洩露使用者密碼等敏感資訊。在 Django 5.0 中變更新增了對包裝
async
函式的支援。
自訂錯誤報告¶
sensitive_variables()
和 sensitive_post_parameters()
所做的分別是,使用敏感變數的名稱來註解被裝飾的函式,以及使用敏感 POST 參數的名稱來註解 HttpRequest
物件,以便在發生錯誤時,這些敏感資訊可以稍後從報告中過濾掉。實際的過濾是由 Django 的預設錯誤報告器過濾器 django.views.debug.SafeExceptionReporterFilter
完成的。當產生錯誤報告時,此過濾器會使用裝飾器的註解來將對應的值替換為星號(**********
)。如果你想為你的整個網站覆寫或自訂此預設行為,你需要定義你自己的過濾器類別,並通過 DEFAULT_EXCEPTION_REPORTER_FILTER
設定告訴 Django 使用它。
DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"
你也可以透過設定 HttpRequest
的 exception_reporter_filter
屬性,以更細微的方式控制在任何給定視圖中使用哪個過濾器。
def my_view(request):
if request.user.is_authenticated:
request.exception_reporter_filter = CustomExceptionReporterFilter()
...
你的自訂過濾器類別需要繼承自 django.views.debug.SafeExceptionReporterFilter
,並且可以覆寫以下屬性和方法:
- class SafeExceptionReporterFilter[原始碼]¶
- cleansed_substitute¶
用來替換敏感值的字串值。預設情況下,它會將敏感變數的值替換為星號(
**********
)。
一個已編譯的正規表示式物件,用於匹配被視為敏感的設定和
request.META
值。預設等同於import re re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
- is_active(request)[原始碼]¶
返回
True
以在get_post_parameters()
和get_traceback_frame_variables()
中啟用過濾。預設情況下,如果DEBUG
為False
,則過濾器會被啟用。請注意,如DEBUG
文件中所述,敏感的request.META
值始終會與敏感的設定值一起過濾。
- get_post_parameters(request)[原始碼]¶
返回已過濾的 POST 參數字典。敏感值會被替換為
cleansed_substitute
。
- get_traceback_frame_variables(request, tb_frame)[原始碼]¶
返回給定回溯框架的已過濾區域變數字典。敏感值會被替換為
cleansed_substitute
。
如果你需要自訂錯誤報告,而不僅僅是過濾,你可以透過定義 DEFAULT_EXCEPTION_REPORTER
設定來指定自訂錯誤報告器類別。
DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"
異常報告器負責編譯異常報告資料,並將其格式化為文字或 HTML(異常報告器在準備異常報告資料時會使用 DEFAULT_EXCEPTION_REPORTER_FILTER
)。
你的自訂報告器類別需要繼承自 django.views.debug.ExceptionReporter
。
- class ExceptionReporter[原始碼]¶
- html_template_path[原始碼]¶
屬性,返回一個
pathlib.Path
,表示用於呈現異常 HTML 表示形式的範本的絕對檔案系統路徑。預設為 Django 提供的範本。
- text_template_path[原始碼]¶
屬性,回傳一個
pathlib.Path
,代表用來呈現例外狀況純文字格式的範本的絕對檔案系統路徑。預設為 Django 提供的範本。
如同篩選器類別,您可以在任何指定的檢視中設定 HttpRequest
的 exception_reporter_class
屬性,以控制要使用哪個例外狀況報告類別。
def my_view(request):
if request.user.is_authenticated:
request.exception_reporter_class = CustomExceptionReporter()
...