---
title: "如何管理错误报告"
version: 4.0
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/4.0/howto/error-reporting/
canonical: https://djangodocs.dev/zh-hans/4.0/howto/error-reporting/
---
# 如何管理错误报告

当您运行着公开的网页时，你应该把设置中的 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 选项设为关闭。 这将使您的服务器运行得更快，并且还可以防止恶意用户在错误页面中看到应用的详细信息。

然而，把配置 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 设置为 False， 这意味着你永远不会在你的网站上看到错误的细节，所有的人相应会看到你公开的错误页面。当你需要在部署的网页上追踪出现的错误，Django 可以通过设置去报告错误的细节。

## 通过邮件方式报告

### 服务器错误

当 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 为 `False` 时，Django 会在代码抛出的异常未被捕获且导致一个内部的服务器错误（HTTP 状态码 500）时向 [`ADMINS`](/zh-hans/4.0/ref/settings/#std-setting-ADMINS) 配置中列出的用户发送邮件。这让管理员立刻收到错误通知。 [`ADMINS`](/zh-hans/4.0/ref/settings/#std-setting-ADMINS) 列表中的用户，会收到详细的错误描述，完整的 Python 调用栈，和引发此错误的 HTTP 请求的细节。

> **Note**
>
> 要发送邮件，Django 要求一些配置项，告诉它如何连接至邮件服务器。最小配置下，你需要指定 [`EMAIL_HOST`](/zh-hans/4.0/ref/settings/#std-setting-EMAIL_HOST) 和 [`EMAIL_HOST_USER`](/zh-hans/4.0/ref/settings/#std-setting-EMAIL_HOST_USER) 和 [`EMAIL_HOST_PASSWORD`](/zh-hans/4.0/ref/settings/#std-setting-EMAIL_HOST_PASSWORD)，可能还有其它配置，这取决于邮件服务器的配置。查阅 [Django 配置文档](/zh-hans/4.0/ref/settings/) 获取邮件相关配置的完整列表。

默认情况下，Django 会从 [root@localhost](mailto:root@localhost) 发送邮件。然而，某些邮件服务商拒绝来自该地址的所有邮件。要使用不同的发件人地址，修改 [`SERVER_EMAIL`](/zh-hans/4.0/ref/settings/#std-setting-SERVER_EMAIL) 配置。

要启动该行为，将收件人的邮箱地址放入 [`ADMINS`](/zh-hans/4.0/ref/settings/#std-setting-ADMINS)。

> **See also**
>
> 服务器错误邮件由 logging 框架发出，所以你能通过 [自定义 logging 配置](/zh-hans/4.0/topics/logging/) 自定义该行为。

### 404 错误

Django 也能配置成为已失效的连接发送错误邮件（404 "page not found" 错误）。Django 发送 404 错误邮件的条件：

- [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 为 `False`；
- [`MIDDLEWARE`](/zh-hans/4.0/ref/settings/#std-setting-MIDDLEWARE) 配置包括 [`django.middleware.common.BrokenLinkEmailsMiddleware`](/zh-hans/4.0/ref/middleware/#django.middleware.common.BrokenLinkEmailsMiddleware)。

如果满足这些条件，Django 会在你的代码出现 404 并且请求有引用来源时，给 [`MANAGERS`](/zh-hans/4.0/ref/settings/#std-setting-MANAGERS) 配置中列出的用户发送电子邮件。对于没有引用来源的 404，Django 懒得发邮件——那些通常是人们输入了错误的 URL 或错误的网络机器人。当引用来源等于被请求的 URL 时，它也会忽略 404，因为这种行为也是来自坏掉的网络机器人。

> **Note**
>
> [`BrokenLinkEmailsMiddleware`](/zh-hans/4.0/ref/middleware/#django.middleware.common.BrokenLinkEmailsMiddleware) 必须出现在其他拦截 404 错误的中间件之前，例如 [`LocaleMiddleware`](/zh-hans/4.0/ref/middleware/#django.middleware.locale.LocaleMiddleware) 或者 [`FlatpageFallbackMiddleware`](/zh-hans/4.0/ref/contrib/flatpages/#django.contrib.flatpages.middleware.FlatpageFallbackMiddleware)。把它放在你的 [`MIDDLEWARE`](/zh-hans/4.0/ref/settings/#std-setting-MIDDLEWARE) 配置的顶部。

你可以通过调整配置项 [`IGNORABLE_404_URLS`](/zh-hans/4.0/ref/settings/#std-setting-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`](/zh-hans/4.0/ref/middleware/#django.middleware.common.BrokenLinkEmailsMiddleware) 的行为（例如忽略来自网络爬虫的请求），你需要继承该类，并重写方法。

> **See also**
>
> 404 错误由 logging 框架报告。默认情况下，这些日志记录被忽略了，但你能通过编写一个处理器和 [配置 logging](/zh-hans/4.0/topics/logging/) 让它们报告错误。

## 过滤错误报告

> **Warning**
>
> 过滤敏感数据是一个很难的问题，几乎不可能保证敏感数据不会泄漏到错误报告中。因此，错误报告应该只提供给受信任的团队成员，你应该避免在互联网上传输未加密的错误报告（如通过电子邮件）。

### 过滤敏感数据

错误报告对于调试错误来说超级有用，所以通常尽可能多的记录关键信息。例如，Django 默认记录了抛出异常的 [完整调用栈](https://en.wikipedia.org/wiki/Stack_frame)，每个 [调用栈层](https://en.wikipedia.org/wiki/Stack_trace) 的局部变量，以及 [`HttpRequest`](/zh-hans/4.0/ref/request-response/#django.http.HttpRequest) 的 [属性](/zh-hans/4.0/ref/request-response/#httprequest-attributes)。

然而，有时候某些信息会涉及敏感内容，因此不适合写入调用栈。例如，用户的密码或信用卡号。故此，为了过滤 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 文档中描述的敏感内容，Django 提供了一系列的函数装饰器，帮你控制在生产环境（即 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 为 `False`）下应该从错误报告中过滤掉哪些信息：[`sensitive_variables()`](#django.views.decorators.debug.sensitive_variables) 和 [`sensitive_post_parameters()`](#django.views.decorators.debug.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 参数`](/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.POST) 的 [`HttpRequest`](/zh-hans/4.0/ref/request-response/#django.http.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`](/zh-hans/4.0/topics/auth/default/#module-django.contrib.auth.views) （`login`， `password_reset_confirm`， `password_change`， and `add_view` 和 `auth` 后台中的 `user_change_password`）的 POST 参数都在错误报告中经过系统过滤。

### 自定义错误报告

[`sensitive_variables()`](#django.views.decorators.debug.sensitive_variables) 和 [`sensitive_post_parameters()`](#django.views.decorators.debug.sensitive_post_parameters) 所做的全部工作是，前者用敏感变量名注解被装饰的函数，后者用 POST 参数中的敏感变量名注解 `HttpRequest` 对象，所以敏感信息能在后续错误发生时从报告中过滤出去。这项过滤操作者实际上是由 Django 的默认错误报告处理器类： [`django.views.debug.SafeExceptionReporterFilter`](#django.views.debug.SafeExceptionReporterFilter)。该过滤器在错误报告生成时，利用装饰器注解以星号 (`**********`) 替换指定值。若你想在全网页范围重写或自定义该默认行为，你需要定义你的过滤器类，并通过配置项 [`DEFAULT_EXCEPTION_REPORTER_FILTER`](/zh-hans/4.0/ref/settings/#std-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`](#django.views.debug.SafeExceptionReporterFilter) 并重写以下属性和方法：

#### `class SafeExceptionReporterFilter`

#### `cleansed_substitute`

用于替换敏感值的字符串。默认情况下，它将敏感参数的值替换成星号 (\*\*\*\*\*\*\*\*\*\*)。

#### `hidden_settings`

一个编译了的用于匹配配置和 `request.META` 值的不忽略大写的正则表达式对象。默认相当于

```
import re

re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.IGNORECASE)
```

#### `is_active(request)`

返回 `True` 以在 [`get_post_parameters()`](#django.views.debug.SafeExceptionReporterFilter.get_post_parameters) 和 [`get_traceback_frame_variables()`](#django.views.debug.SafeExceptionReporterFilter.get_traceback_frame_variables) 中激活过滤。默认情况下如果配置 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 为 `False` 则过滤器会启动。请注意，就像文档中配置 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 描述的一样，敏感的 `request.META` 请求值总是会以配置好的值过滤掉。

#### `get_post_parameters(request)`

返回POST参数过滤后的字典。敏感参数的值会被替换成 [`cleansed_substitute`](#django.views.debug.SafeExceptionReporterFilter.cleansed_substitute)。

#### `get_traceback_frame_variables(request, tb_frame)`

返回给定的调用栈层中的局部变量经过过滤后的字段。敏感值会被替换成 [`cleansed_substitute`](#django.views.debug.SafeExceptionReporterFilter.cleansed_substitute)。

如果你需要在过滤器之外自定义错误报告，你可以指定一个自定义写在配置 [`DEFAULT_EXCEPTION_REPORTER`](/zh-hans/4.0/ref/settings/#std-setting-DEFAULT_EXCEPTION_REPORTER) setting:: 配置的错误报告类

```
DEFAULT_EXCEPTION_REPORTER = 'path.to.your.CustomExceptionReporter'
```

异常报告工具负责编译异常报告并将其整理成文本或HTML文件的形式。（当准备要报告的异常数据的时候异常报告工具使用配置 [`DEFAULT_EXCEPTION_REPORTER_FILTER`](/zh-hans/4.0/ref/settings/#std-setting-DEFAULT_EXCEPTION_REPORTER_FILTER) ）

你的自定义的报告类需要继承自类 :class: django.views.debug.ExceptionReporter 。

#### `class ExceptionReporter`

#### `html_template_path`

> **New in Django 3.2**

返回一个 [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path) 的类，该路径表示模板的绝对文件系统路径，用于呈现异常的 HTML 表示。 默认为 Django 提供的模板。

#### `text_template_path`

> **New in Django 3.2**

返回一个 [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#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()
    ...
```

> **See also**
>
> 你也能够通过自定义一系列的 [异常中间层](/zh-hans/4.0/topics/http/middleware/#exception-middleware) 定制错误报告行为。若你已经编写了自定义错误处理器，模仿 Django 内置的错误处理器，并只在 [`DEBUG`](/zh-hans/4.0/ref/settings/#std-setting-DEBUG) 为 `False` 时报告或记录错误是个不错的主意。
