如何管理错误报告¶
当你运行一个公共网站时,你应该始终关闭DEBUG
设置。这将使你的服务器运行得更快,并且还可以防止恶意用户看到错误页面中可能透露的你的应用程序的详细信息。
但是,使用DEBUG
设置为False
运行意味着你将永远看不到你的网站生成的错误 - 相反,每个人都将看到你的公共错误页面。你需要跟踪已部署网站中发生的错误,因此可以配置 Django 来创建包含有关这些错误的详细信息的报告。
电子邮件报告¶
服务器错误¶
当 DEBUG
为 False
时,Django 将向 ADMINS
设置中列出的用户发送电子邮件,只要你的代码引发未处理的异常并导致内部服务器错误(严格来说,对于任何 HTTP 状态代码为 500 或更大的响应)。这会让管理员立即收到任何错误的通知。 ADMINS
将收到错误描述、完整的 Python 回溯以及导致错误的 HTTP 请求的详细信息。
注意
为了发送电子邮件,Django 需要一些设置来告诉它如何连接到你的邮件服务器。至少,你需要指定 EMAIL_HOST
,可能还需要 EMAIL_HOST_USER
和 EMAIL_HOST_PASSWORD
,尽管其他设置也可能是必需的,具体取决于你的邮件服务器的配置。请参阅 Django 设置文档 以获取与电子邮件相关的设置的完整列表。
默认情况下,Django 将从 root@localhost 发送电子邮件。但是,一些邮件提供商会拒绝来自此地址的所有电子邮件。要使用不同的发件人地址,请修改 SERVER_EMAIL
设置。
要激活此行为,请将收件人的电子邮件地址放入 ADMINS
设置中。
另请参阅
服务器错误电子邮件是使用日志记录框架发送的,因此你可以通过 自定义日志记录配置 来自定义此行为。
404 错误¶
Django 还可以配置为发送有关损坏链接(404 “页面未找到”错误)的错误电子邮件。当
DEBUG
为False
时,Django 会发送有关 404 错误的电子邮件;- 您的
MIDDLEWARE
设置包括django.middleware.common.BrokenLinkEmailsMiddleware
。
如果满足这些条件,Django 将在您的代码引发 404 并且请求具有引用者时,向 MANAGERS
设置中列出的用户发送电子邮件。它不会费心为没有引用者的 404 发送电子邮件 - 这些通常是输入损坏的 URL 或损坏的网络机器人的用户。当引用者等于请求的 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 parameters
,则可以使用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
以及add_view
和user_change_password
在auth
管理中),所有 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)
在 Django 4.2 中更改添加了
HTTP_COOKIE
。
-
is_active
(request)¶ 返回
True
以激活get_post_parameters()
和get_traceback_frame_variables()
中的过滤。默认情况下,如果DEBUG
为False
,则过滤器处于活动状态。请注意,敏感request.META
值始终与敏感设置值一起过滤,如DEBUG
文档中所述。
-
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 提供的模板。
-
get_traceback_data
()¶ 返回包含回溯信息的字典。
这是用于自定义异常报告的主要扩展点,例如
from django.views.debug import ExceptionReporter class CustomExceptionReporter(ExceptionReporter): def get_traceback_data(self): data = super().get_traceback_data() # ... remove/add something here ... return data
-
get_traceback_html
()¶ 返回异常报告的 HTML 版本。
用于调试 500 HTTP 错误页面的 HTML 版本。
-
get_traceback_text
()¶ 返回异常报告的纯文本版本。
用于调试 500 HTTP 错误页面和电子邮件报告的纯文本版本。
-
与过滤器类一样,你可以通过设置 HttpRequest
的 exception_reporter_class
属性来控制在任何给定视图中使用哪个异常报告器类
def my_view(request):
if request.user.is_authenticated:
request.exception_reporter_class = CustomExceptionReporter()
...