如何管理错误报告¶
当您运行着公开的网页时,你应该把设置中的 DEBUG 选项设为关闭。 这将使您的服务器运行得更快,并且还可以防止恶意用户在错误页面中看到应用的详细信息。
然而,把配置 DEBUG 设置为 False, 这意味着你永远不会在你的网站上看到错误的细节,所有的人相应会看到你公开的错误页面。当你需要在部署的网页上追踪出现的错误,Django 可以通过设置去报告错误的细节。
通过邮件方式报告¶
服务器错误¶
当 DEBUG 为 False 时,Django 会在代码抛出的异常未被捕获且导致一个内部的服务器错误(HTTP 状态码 500)时向 ADMINS 配置中列出的用户发送邮件。这让管理员立刻收到错误通知。 ADMINS 列表中的用户,会收到详细的错误描述,完整的 Python 调用栈,和引发此错误的 HTTP 请求的细节。
备注
要发送邮件,Django 要求一些配置项,告诉它如何连接至邮件服务器。最小配置下,你需要指定 EMAIL_HOST 和 EMAIL_HOST_USER 和 EMAIL_HOST_PASSWORD,可能还有其它配置,这取决于邮件服务器的配置。查阅 Django 配置文档 获取邮件相关配置的完整列表。
默认情况下,Django 会从 root@localhost 发送邮件。然而,某些邮件服务商拒绝来自该地址的所有邮件。要使用不同的发件人地址,修改 SERVER_EMAIL 配置。
要启动该行为,将收件人的邮箱地址放入 ADMINS。
参见
服务器错误邮件由 logging 框架发出,所以你能通过 自定义 logging 配置 自定义该行为。
404 错误¶
Django 也能配置成为已失效的连接发送错误邮件(404 "page not found" 错误)。Django 发送 404 错误邮件的条件:
- DEBUG为- False;
- MIDDLEWARE配置包括- django.middleware.common.BrokenLinkEmailsMiddleware。
如果满足这些条件,Django 会在你的代码出现 404 并且请求有引用来源时,给 MANAGERS 配置中列出的用户发送电子邮件。对于没有引用来源的 404,Django 懒得发邮件——那些通常是人们输入了错误的 URL 或错误的网络机器人。当引用来源等于被请求的 URL 时,它也会忽略 404,因为这种行为也是来自坏掉的网络机器人。
备注
BrokenLinkEmailsMiddleware 必须出现在其他拦截 404 错误的中间件之前,例如 LocaleMiddleware 或者 FlatpageFallbackMiddleware。把它放在你的 MIDDLEWARE 配置的顶部。
你可以通过调整配置项 IGNORABLE_404_URLS 让 Django 忽略某些 404s。内容应该是已编译的正则表达式的列表。例子:
import re
IGNORABLE_404_URLS = [
    re.compile(r"\.(php|cgi)$"),
    re.compile(r"^/phpmyadmin/"),
]
在本例中,对以 .php 或 .cgi 结尾的 URL 的 404 错误将 不会 被报告。以 phpmyadmin 开头的也不会被报告。
下面的例子展示了如何排除一些浏览器和爬虫经常访问的传统 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 错误由 logging 框架报告。默认情况下,这些日志记录被忽略了,但你能通过编写一个处理器和 配置 logging 让它们报告错误。
过滤错误报告¶
警告
过滤敏感数据是一个很难的问题,几乎不可能保证敏感数据不会泄漏到错误报告中。因此,错误报告应该只提供给受信任的团队成员,你应该避免在互联网上传输未加密的错误报告(如通过电子邮件)。
过滤敏感数据¶
错误报告对于调试错误来说超级有用,所以通常尽可能多的记录关键信息。例如,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): ... - 警告 - 由于需要跨同步/异步边界的机制, - sync_to_async()和- async_to_sync()不兼容- sensitive_variables()。- 如果在使用这些适配器时涉及敏感变量,请确保审查异常报告,并在必要时考虑实现 自定义过滤器。 
- 
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"], ) ... - 上文例子中,POST 参数 - pass_word和- credit_card_number的值会被隐藏,通过在错误报告中展示请求信息的地方用星号开头的字符串 (- **********)替换,而参数- name的值不会被屏蔽。- 要在错误报告中系统的屏蔽所有 POST 参数,不要给 - sensitive_post_parameters装饰器提供任何参数:- @sensitive_post_parameters() def my_view(request): ... - 为了避免敏感信息的泄露(例如账号密码), 所有传入认证视图 - django.contrib.auth.views(- login,- password_reset_confirm,- password_change, and- add_view和- auth后台中的- user_change_password)的 POST 参数都在错误报告中经过系统过滤。
自定义错误报告¶
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) Changed in Django 4.2:- 添加了 - HTTP_COOKIE。
 - 
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 setting:: 配置的错误报告类
DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"
异常报告工具负责编译异常报告并将其整理成文本或HTML文件的形式。(当准备要报告的异常数据的时候异常报告工具使用配置 DEFAULT_EXCEPTION_REPORTER_FILTER )
你的自定义的报告类需要继承自类 :class: 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版本。 - 用于返回HTTP 500错误页面的HTML版本。 
 - 
get_traceback_text()¶
- 返回异常报告的纯文本版本。 - 用于调试HTTP 500错误页面和相应邮件报告的纯文本版本。 
 
- 
和过滤类一样,你也能在任意视图内通过配置 HttpRequest 的 exception_reporter_filter 属性来控制具体使用哪个错误报告类:
def my_view(request):
    if request.user.is_authenticated:
        request.exception_reporter_class = CustomExceptionReporter()
    ...
 
          