错误报告 — Django 文档
错误报告
当您运行公共站点时,您应该始终关闭 :setting:`DEBUG` 设置。 这将使您的服务器运行得更快,并且还可以防止恶意用户看到您的应用程序的详细信息,这些详细信息可以通过错误页面显示出来。
但是,在 :setting:`DEBUG` 设置为 False
的情况下运行意味着您永远不会看到您的站点生成的错误——每个人都会看到您的公共错误页面。 您需要跟踪已部署站点中发生的错误,因此可以将 Django 配置为创建包含这些错误详细信息的报告。
电子邮件报告
服务器错误
当 :setting:`DEBUG` 为 False
时,每当您的代码引发未处理的异常并且导致内部服务器错误(严格来说,对于 HTTP 状态代码为 500 或更大的任何响应)。 这为管理员提供了任何错误的即时通知。 :setting:`ADMINS` 将获得错误描述、完整的 Python 回溯以及有关导致错误的 HTTP 请求的详细信息。
笔记
为了发送电子邮件,Django 需要一些设置来告诉它如何连接到您的邮件服务器。 至少,您需要指定 :setting:`EMAIL_HOST` 和可能的 :setting:`EMAIL_HOST_USER` 和 :setting:`EMAIL_HOST_PASSWORD` ,但可能还需要其他设置,具体取决于您的邮件服务器的配置。 有关电子邮件相关设置的完整列表,请参阅 Django 设置文档 。
默认情况下,Django 将从 root@localhost 发送电子邮件。 但是,某些邮件提供商拒绝来自此地址的所有电子邮件。 要使用不同的发件人地址,请修改 :setting:`SERVER_EMAIL` 设置。
要激活此行为,请将收件人的电子邮件地址放入 :setting:`ADMINS` 设置中。
404错误
Django 还可以配置为通过电子邮件发送有关断开链接的错误(404“找不到页面”错误)。 在以下情况下,Django 会发送关于 404 错误的电子邮件:
- :setting:`DEBUG` 是
False
; - 您的 :setting:`MIDDLEWARE` 设置包括 django.middleware.common.BrokenLinkEmailsMiddleware。
如果满足这些条件,每当您的代码引发 404 并且请求有引用者时,Django 都会向 :setting:`MANAGERS` 设置中列出的用户发送电子邮件。 对于没有引用者的 404 发送电子邮件并不费心——这些通常是人们输入损坏的 URL 或损坏的 Web 机器人。 当引用者等于请求的 URL 时,它也会忽略 404,因为这种行为也来自损坏的 Web 机器人。
笔记
BrokenLinkEmailsMiddleware必须出现在其他拦截404错误的中间件之前,例如LocaleMiddleware或FlatpageFallbackMiddleware。 将它放在 :setting:`MIDDLEWARE` 设置的顶部。
您可以通过调整 :setting:`IGNORABLE_404_URLS` 设置来告诉 Django 停止报告特定的 404。 它应该是一个已编译的正则表达式对象列表。 例如:
import re
IGNORABLE_404_URLS = [
re.compile(r'\.(php|cgi)$'),
re.compile(r'^/phpmyadmin/'),
]
在此示例中,任何以 .php
或 .cgi
结尾的 URL 的 404 将被报告为 not。 任何以 /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 的行为(例如忽略来自网络爬虫的请求),您应该将其子类化并覆盖其方法。
过滤错误报告
警告
过滤敏感数据是一个难题,几乎不可能保证敏感数据不会泄漏到错误报告中。 因此,错误报告应该只提供给受信任的团队成员,并且您应该避免通过 Internet(例如通过电子邮件)传输未加密的错误报告。
过滤敏感信息
错误报告对于调试错误非常有帮助,因此记录尽可能多的关于这些错误的相关信息通常很有用。 例如,默认情况下,Django 会记录引发异常的 完整回溯 、每个 回溯框架 的局部变量以及 HttpRequest 的 属性。
然而,有时某些类型的信息可能过于敏感,因此可能不适合跟踪,例如用户的密码或信用卡号。 因此,除了过滤掉 :setting:`DEBUG` 文档中描述的敏感设置之外,Django 还提供了一组函数装饰器来帮助您控制哪些信息应该从错误报告中过滤掉在生产环境中(即 :setting:`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): ...
- sensitive_post_parameters(*parameters)
如果您的视图之一收到带有 POST 参数 的 HttpRequest 对象,该对象容易包含敏感信息,您可以使用
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
和 [ X160X] 和user_change_password
在auth
admin) 中防止泄露用户密码等敏感信息。
自定义错误报告
sensitive_variables() 和 sensitive_post_parameters() 所做的就是分别用敏感变量的名称注释修饰函数,用敏感变量的名称注释 HttpRequest
对象POST 参数,以便稍后在发生错误时可以从报告中过滤掉这些敏感信息。 实际的过滤是由 Django 的默认错误报告过滤器完成的:django.views.debug.SafeExceptionReporterFilter。 当产生错误报告时,这个过滤器使用装饰器的注解用星号 (**********
) 替换相应的值。 如果您希望为整个站点覆盖或自定义此默认行为,则需要定义自己的过滤器类并通过 :setting:`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
3.1 版中的新功能。
要替换敏感值的字符串值。 默认情况下,它用星号 (
**********
) 替换敏感变量的值。
- hidden_settings
3.1 版中的新功能。
用于匹配设置和被视为敏感的
request.META
值的已编译正则表达式对象。 默认相当于:import re re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.IGNORECASE)
- is_active(request)
返回
True
以激活 get_post_parameters() 和 get_traceback_frame_variables() 中的过滤。 默认情况下,如果 :setting:`DEBUG` 是False
,则过滤器处于活动状态。 请注意,敏感request.META
值始终与敏感设置值一起过滤,如 :setting:`DEBUG` 文档中所述。
- get_post_parameters(request)
返回过滤后的 POST 参数字典。 敏感值被替换为 cleansed_substitute。
- get_traceback_frame_variables(request, tb_frame)
返回给定回溯框架的局部变量过滤字典。 敏感值被替换为 cleansed_substitute。
3.1 版中的新功能。
如果您需要在过滤之外自定义错误报告,您可以通过定义 :setting:`DEFAULT_EXCEPTION_REPORTER` 设置来指定自定义错误报告器类:
DEFAULT_EXCEPTION_REPORTER = 'path.to.your.CustomExceptionReporter'
异常报告者负责编译异常报告数据,并适当地将其格式化为文本或 HTML。 (异常报告器在准备异常报告数据时使用 :setting:`DEFAULT_EXCEPTION_REPORTER_FILTER`。)
您的自定义报告器类需要从 django.views.debug.ExceptionReporter 继承。
- class ExceptionReporter
- 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()
...
也可以看看
您还可以通过编写自定义的 异常中间件 来设置自定义错误报告。 如果您确实编写了自定义错误处理,最好模拟 Django 的内置错误处理,并且仅在 :setting:`DEBUG` 为 False
时才报告/记录错误。