# Django 3.2.11.dev 文档

# 中间件

这篇文档解释了所有 Django 自带的中间件组件。关于如何使用它们以及如何编写自己的中间件，请参见 中间件使用指南。

## 可用的中间件

### 缓存中间件

class `UpdateCacheMiddleware`

class `FetchFromCacheMiddleware`

启用全站缓存。如果启用了这些功能，那么每一个 Django 驱动的页面都会在 `CACHE_MIDDLEWARE_SECONDS` 配置定义的时间内被缓存。参见 缓存文档。

### “通用”中间件

class `CommonMiddleware`

为完美主义者增加了一些便利：

- 禁止 `DISALLOWED_USER_AGENTS` 配置中的用户代理访问，它应该是一个编译的正则表达式对象列表。

- 根据 `APPEND_SLASH` 和 `PREPEND_WWW` 的配置进行 URL 重写。

  如果 `APPEND_SLASH` 为 `True`，并且初始的 URL 没有以斜线结尾，而且在 URLconf 中也没有找到，那么就会在最后附加一个斜线形成一个新的 URL。如果在 URLconf 中找到了这个新的 URL，那么 Django 会将请求重定向到这个新的 URL。否则，初始的 URL 就会被照常处理。

  例如，`foo.com/bar` 将被重定向到 `foo.com/bar/`，如果你没有 `foo.com/bar` 的有效 URL 模式，但 有 `foo.com/bar/` 的有效模式。

  如果 `PREPEND_WWW` 为 `True`，缺乏前导“www. ”的 URL 将被重定向到带有前导“www. ”的同一 URL。

  这两个选项都是为了规范 URL。其理念是，每个 URL 应该存在于一个地方，而且只有一个地方。从技术上讲，URL `foo.com/bar` 与 `foo.com/bar/` 是不同的——搜索引擎索引器会将它们视为单独的 URL——所以最好的做法是将 URL 规范化。

  如果有必要，可以使用 `no_append_slash()` 装饰器将个别视图从 `APPEND_SLASH` 行为中排除：

      from django.views.decorators.common import no_append_slash

      @no_append_slash
      def sensitive_fbv(request, *args, **kwargs):
          """View to be excluded from APPEND_SLASH."""
          return HttpResponse()

  Changed in Django 3.2:

  增加了对 `no_append_slash()` 装饰器的支持。

- 设置非流响应的 `Content-Length` 头。

`CommonMiddleware.``response_redirect_class`

默认为 `HttpResponsePermanentRedirect`。子类化 `CommonMiddleware`，并重写该属性来定制中间件发出的重定向。

class `BrokenLinkEmailsMiddleware`

- 向 `manager` 发送失效链接通知邮件（参见 发送错误）。

### GZip 中间件

class `GZipMiddleware`

警告

安全研究人员最近发现，当在网站上使用压缩技术（包括 `GZipMiddleware`）时，网站可能会受到一些可能的攻击。在你的网站上使用 `GZipMiddleware` 之前，你应该仔细考虑你是否会受到这些攻击。如果你对你是否受到影响有 任何 怀疑，你应该避免使用 `GZipMiddleware`。更多细节，请看 the BREACH paper (PDF) 和 breachattack.com 。

`django.middleware.gzip.GZipMiddleware` 为能理解 GZip 压缩的浏览器（所有现代浏览器）压缩内容。

这个中间件应该放在任何其他需要读取或写入响应体的中间件之前，这样压缩就会在之后发生。

如果以下任何一项为真，它将不会压缩内容：

- 内容主体长度小于 200 字节。
- 响应已经设置了 `Content-Encoding` 头。
- 请求（浏览器）没有发送包含 `gzip` 的 `Accept-Encoding` 头。

如果响应有 `ETag` 头，则 ETag 会变得很弱，以符合 RFC 7232#section-2.1。

你可以使用 `gzip_page()` 装饰器对单个视图应用 GZip 压缩。

### 条件 GET 中间件

class `ConditionalGetMiddleware`

处理有条件的 GET 操作。如果响应没有 `ETag` 头，中间件会根据需要添加一个。如果响应有 `ETag` 或 `Last-Modified` 头，而请求有 `If-None-Match` 或 `If-Modified-Since`，则响应被一个 `HttpResponseNotModified` 替换。

### 本地化中间件

class `LocaleMiddleware`

可以根据请求的数据选择语言。它为每个用户定制内容。请参阅 国际化文档。

`LocaleMiddleware.``response_redirect_class`

默认为 `HttpResponseRedirect`。子类化 `LocaleMiddleware` 并重写该属性，以自定义中间件发出的重定向。

### 消息中间件

class `MessageMiddleware`

启用基于 cookie 和会话的消息支持。参见 消息文档。

### 安全中间件

警告

如果你的部署情况允许，通常让你的前端 Web 服务器执行“安全中间件”提供的功能是个好主意。这样一来，如果有一些请求不是由 Django 服务的（比如静态资源或用户上传的文件），它们将和对你的 Django 应用的请求有同样的保护。

class `SecurityMiddleware`

`django.middleware.security.SecurityMiddleware` 为请求／响应周期提供了若干安全增强功能。每一项都可以通过设置独立地启用或禁用。

- `SECURE_BROWSER_XSS_FILTER`
- `SECURE_CONTENT_TYPE_NOSNIFF`
- `SECURE_HSTS_INCLUDE_SUBDOMAINS`
- `SECURE_HSTS_PRELOAD`
- `SECURE_HSTS_SECONDS`
- `SECURE_REDIRECT_EXEMPT`
- `SECURE_REFERRER_POLICY`
- `SECURE_SSL_HOST`
- `SECURE_SSL_REDIRECT`

#### HTTP 严格传输安全

对于只能通过 HTTPS 访问的网站，你可以通过设置 "Strict-Transport-Security" 头 来指示现代浏览器拒绝通过不安全的连接连接到你的域名（在给定的时间内）。这可以减少你受到一些 SSL 剥离中间人（MITM）的攻击。

如果你将 `SECURE_HSTS_SECONDS` 设置为一个非零的整数值，`SecurityMiddleware` 将为你在所有 HTTPS 响应中设置这个头。

当启用 HSTS 时，最好先使用一个小值进行测试，例如 `SECURE_HSTS_SECONDS=3600` 为一小时。每次 Web 浏览器看到你的网站的 HSTS 头时，它将在给定的时间内拒绝与你的域名进行非安全通信（使用 HTTP）。一旦你确认你的网站上所有的资产都是安全服务的（即 HSTS 没有破坏任何东西），最好是增加这个值，这样不经常访问的人就会受到保护（31536000秒，即 1 年，是常见的）。

此外，如果你将 `SECURE_HSTS_INCLUDE_SUBDOMAINS` 设置为 `True`，`SecurityMiddleware` 将在 `Strict-Transport-Security` 头中添加 `includeSubDomains` 指令。建议这样做（假设所有的子域都只使用 HTTPS 服务），否则你的网站仍然可能通过不安全的连接到子域而受到攻击。

如果你希望将你的网站提交到 浏览器预加载列表 ，请将 `SECURE_HSTS_PRELOAD` 设置为 `True`。这样就会把 `preload` 指令附加到 `Strict-Transport-Security` 头。

警告

HSTS 策略适用于你的整个域，而不仅仅是你设置响应头的 URL。因此，你应该只在你的整个域名只通过 HTTPS 服务时使用它。

适当尊重 HSTS 头的浏览器将拒绝允许用户绕过警告，并连接到使用过期、自签名或其他无效 SSL 证书的网站。如果你使用 HSTS，请确保你的证书处于良好状态，并保持这种状态！

注解

如果你部署在负载平衡器或反向代理服务器后面，而 `Strict-Transport-Security` 头没有被添加到你的响应中，这可能是因为 Django 没有意识到它是在一个安全的连接上；你可能需要设置 `SECURE_PROXY_SSL_HEADER` 设置。

#### Referrer 政策

浏览器使用 referer 头 作为向网站发送关于用户如何到达那里的信息的一种方式。当用户点击一个链接时，浏览器将发送链接页面的完整 URL 作为 referrer。虽然这对某些目的来说可能很有用——例如查明谁在链接到你的网站——但它也可能引起隐私问题，因为它告诉一个网站，一个用户正在访问另一个网站。

一些浏览器能够接受关于是否应该在用户点击链接时发送 HTTP `Referer` 头的提示；这种提示通过 Referrer-Policy 头 提供。这个头可以向浏览器建议三种行为中的任何一种：

- 完整 URL：在 `Referer` 头中发送整个URL。例如，如果用户访问 `https://example.com/page.html`，`Referer` 头将包含 `"https://example.com/page.html"`。
- 仅起源：只发送 referrer 中的“起源”。起源由方案、主机和（可选）端口号组成。例如，如果用户访问的是 `https://example.com/page.html`，起源就是 `https://example.com/`。
- 无 referrer：完全不发送 `Referer` 头。

有两种类型的情况，这个头可以告诉浏览器要注意：

- 同源与跨源：从 `https://example.com/1.html` 到 `https://example.com/2.html` 的链接为同源链接。从 `https://example.com/page.html` 到 `https://not.example.com/page.html` 的链接为跨源链接。
- 协议降级：如果包含链接的页面是通过 HTTPS 服务的，但被链接的页面不是通过 HTTPS 服务的，就会发生降级。

警告

当你的网站通过 HTTPS 提供服务时， Django 的 CSRF 保护系统 需要 `Referer` 头存在，所以完全禁用 `Referer` 头会干扰 CSRF 保护。要想在保留 CSRF 保护的同时，获得禁用 `Referer` 头的大部分好处，可以考虑只启用同源引用。

`SecurityMiddleware` 可以根据 `SECURE_REFERRER_POLICY` 设置，为你设置 `Referrer-Policy` 头（注意拼写：当用户点击链接时，浏览器会发送一个 `Referer` 头，但指示浏览器是否这样做的头是拼写为 `Referrer-Policy`）。该设置的有效值为：

`no-referrer`
  指示浏览器对在本网站上点击的链接不发送 referrer。
`no-referrer-when-downgrade`
  指示浏览器发送完整的 URL 作为 referrer，但只有在没有发生协议降级的情况下。
`origin`
  指示浏览器只发送起源，而不是完整的 URL 作为 referrer。
`origin-when-cross-origin`
  指示浏览器发送完整的 URL 作为同源链接的 referrer，而只发送起源给跨源链接。
`same-origin`
  指示浏览器发送完整的 URL，但只针对同源链接。对于跨源链接，将不发送 referrer。
`strict-origin`
  指示浏览器只发送起源，而不是完整的 URL，并在协议降级时不发送 referrer。
`strict-origin-when-cross-origin`
  当链接为同源且不发生协议降级时，指示浏览器发送完整的 URL；当链接为跨源且不发生协议降级时，只发送起源；当发生协议降级时，不发送 referrer。
`unsafe-url`
  指示浏览器始终发送完整的 URL 作为 referrer。

未知政策值

当一个策略值被用户代理认为 未知 时，可以指定多个策略值以提供后备。最后一个被理解的指定值优先。为了支持这一点，可以在 `SECURE_REFERRER_POLICY` 中使用一个可迭代对象或逗号分隔的字符串。

#### `X-Content-Type-Options: nosniff`

一些浏览器会试图猜测它们获取的资源的内容类型，覆盖 `Content-Type` 头。虽然这可以帮助显示配置不当的服务器的网站，但也会带来安全风险。

如果你的网站提供用户上传的文件，恶意用户可能会上传一个特制的文件，当你认为它是无害的东西时，该文件会被浏览器解释为 HTML 或 JavaScript。

为了防止浏览器猜测内容类型，并迫使它总是使用 `Content-Type` 头中提供的类型，你可以传递 X-Content-Type-Options: nosniff 头。 如果 `SECURE_CONTENT_TYPE_NOSNIFF` 设置为 `True`，`SecurityMiddleware` 将对所有的响应进行这样的操作。

需要注意的是，在大多数部署情况下，Django 并不参与服务用户上传的文件，这个设置对你没有帮助。例如，如果你的 `MEDIA_URL` 是由你的前端 Web 服务器（nginx，Apache等）直接提供服务的，那么你会希望在那里设置这个头。另一方面，如果你使用 Django 来做一些事情，比如需要授权才能下载文件，而你又不能用你的 Web 服务器来设置头，那么这个设置就会很有用。

#### `X-XSS-Protection: 1; mode=block`

一些浏览器有能力阻止看起来是 XSS 攻击 的内容。它们的工作原理是在页面的 GET 或 POST 参数中寻找 JavaScript 内容。如果 JavaScript 在服务器的响应中被重放，页面就会被阻止渲染，并显示一个错误页面。

X-XSS-Protection 头 用于控制 XSS 过滤器的操作。

要在浏览器中启用 XSS 过滤器，并强制其始终阻止可疑的 XSS 攻击，你可以通过 `X-XSS-Protection: 1; mode=block` 头。如果 `SECURE_BROWSER_XSS_FILTER` 设置为 `True`，`SecurityMiddleware` 将对所有响应进行此操作。

警告

浏览器 XSS 过滤器是一种有用的防御措施，但不能完全依赖它。它不能检测所有的 XSS 攻击，而且不是所有的浏览器都支持头。确保你仍然 验证和消毒 所有输入，以防止 XSS 攻击。

#### SSL 重定向

如果你的网站同时提供 HTTP 和 HTTPS 连接，大多数用户最终会默认使用不安全的连接。为了达到最佳的安全性，你应该将所有的 HTTP 连接重定向到 HTTPS。

如果你将 `SECURE_SSL_REDIRECT` 设置为 True，`SecurityMiddleware` 将永久（HTTP 301）重定向所有 HTTP 连接到 HTTPS。

注解

出于性能方面的考虑，最好在 Django 之外，在前端负载均衡器或反向代理服务器（如 nginx ）中做这些重定向。 `SECURE_SSL_REDIRECT` 是为了在部署情况下，这不是一个选项。

如果 `SECURE_SSL_HOST` 设置有一个值，所有的重定向将被发送到该主机，而不是最初要求的主机。

如果你的网站上有几个页面应该通过 HTTP 提供，而不是重定向到 HTTPS，你可以在 `SECURE_REDIRECT_EXEMPT` 设置中列出正则表达式来匹配这些 URL。

注解

如果你部署在负载均衡器或反向代理服务器后面，而 Django 似乎无法判断一个请求是否真的已经安全，你可能需要设置 `SECURE_PROXY_SSL_HEADER` 配置。

### 会话中间件

class `SessionMiddleware`

启用会话支持。参见 会话文档。

### 站点中间件

class `CurrentSiteMiddleware`

将代表当前站点的 `site` 属性添加到每个传入的 `HttpRequest` 对象中。参见 站点文档。

### 验证中间件

class `AuthenticationMiddleware`

将代表当前登录的用户的 `user` 属性添加到每个传入的 `HttpRequest` 对象中。见 Web 请求中的验证。

class `RemoteUserMiddleware`

用于利用 Web 服务器提供的认证的中间件。详细使用方法请看 使用 REMOTE_USER 进行身份验证。

class `PersistentRemoteUserMiddleware`

当仅在登录页面启用时，利用 Web 服务器提供的认证的中间件。详细使用方法参见 仅在登录界面使用 REMOTE_USER。

### CSRF 保护中间件

class `CsrfViewMiddleware`

通过在 POST 表单中添加隐藏的表单字段，并检查请求的正确值，增加对跨站点伪造请求的保护。请参阅 跨站点伪造请求保护文档。

### `X-Frame-Options` 中间件

class `XFrameOptionsMiddleware`

简单的 通过 X-Frame-Options 头的点击劫持保护。

## 中间件顺序

下面是关于各种 Django 中间件类的排序的一些提示：

1. `SecurityMiddleware`

   如果你要开启 SSL 重定向，它应该排在列表的最前面，因为这样可以避免运行一堆其他不必要的中间件。

2. `UpdateCacheMiddleware`

   在修改 `Vary` 头（`SessionMiddleware`、`GZipMiddleware`、`LocaleMiddleware`）之前。

3. `GZipMiddleware`

   在任何可能改变或使用响应体的中间件之前。

   在 `UpdateCacheMiddleware` 之后：修改 `Vary` 头。

4. `SessionMiddleware`

   在任何可能引发异常触发错误视图的中间件之前（如 `PermissionDenied`），如果你使用的是 `CSRF_USE_SESSIONS`。

   在 `UpdateCacheMiddleware` 之后：修改 `Vary` 头。

5. `ConditionalGetMiddleware`

   在任何可能改变响应的中间件之前（它设置 `ETag` 头）。

   在 `GZipMiddleware` 之后，这样它就不会在 gzip 压缩后的内容上计算 `ETag` 头。

6. `LocaleMiddleware`

   最上面的一个，仅次于 `SessionMiddleware` （使用会话数据）和 `UpdateCacheMiddleware` （修改 `Vary` 头）。

7. `CommonMiddleware`

   在任何可能改变响应的中间件之前（它设置 `Content-Length` 头）。出现在 `CommonMiddleware` 之前并改变响应的中间件必须重置 `Content-Length`。

   靠近顶部：当 `APPEND_SLASH` 或 `PREPEND_WWW` 设置为 `True` 时，它会重定向。

   在 `SessionMiddleware` 之后，如果你使用 `CSRF_USE_SESSIONS`。

8. `CsrfViewMiddleware`

   在任何假设 CSRF 攻击已经被处理的视图中间件之前。

   在 `RemoteUserMiddleware`，或任何其他可能执行登录的认证中间件，从而旋转 CSRF 令牌，然后再向下调用中间件链。

   在 `SessionMiddleware` 之后，如果你使用 `CSRF_USE_SESSIONS`。

9. `AuthenticationMiddleware`

   `SessionMiddleware` 之后：使用会话存储。

10. `MessageMiddleware`

    `SessionMiddleware` 之后：可以使用基于会话的存储。

11. `FetchFromCacheMiddleware`

    在任何修改 `Vary` 头的中间件之后：该头用于为缓存哈希键选取一个值。

12. `FlatpageFallbackMiddleware`

    应该是接近底部，因为这是一种最后的中间件。

13. `RedirectFallbackMiddleware`

    应该是接近底部，因为这是一种最后的中间件。