---
title: "中间件"
version: 2.1
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/2.1/topics/http/middleware/
canonical: https://djangodocs.dev/zh-hans/2.1/topics/http/middleware/
---
# 中间件

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统，用于全局改变 Django 的输入或输出。

每个中间件组件负责做一些特定的功能。例如，Django 包含一个中间件组件 [`AuthenticationMiddleware`](/zh-hans/2.1/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware)，它使用会话将用户与请求关联起来。

他的文档解释了中间件是如何工作的，如何激活中间件，以及如何编写自己的中间件。Django 具有一些内置的中间件，你可以直接使用。它们被记录在 [built-in middleware reference](/zh-hans/2.1/ref/middleware/) 中。

## 编写自己的中间件

中间件工厂是一个可调用的程序，它接受 `get_response` 可调用并返回中间件。中间件是可调用的，它接受请求并返回响应，就像视图一样。

中间件可以被写成这样的函数：

```
def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware
```

或者它可以写成一个类，它的实例是可调用的，如下：

```
class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response
```

Django 提供的 `get_response` 响应可能是实际视图（如果这是最后列出的中间件），或者它可能是链中的下一个中间件。不需要知道或关心当前的中间件到底是什么，它只是代表了下一步的内容。

以上是一个轻微的简化——链中最后一个中间件调用的 `get_response` 可不是实际视图，而是处理程序的包装方法，它负责应用 [view middleware](#view-middleware)，调用具有适当URL参数的视图，并应用 [template-response](#template-response-middleware) 和 [exception](#exception-middleware) 中间件。

中间件可以放在 Python 路径上的任何地方。

### `__init__(get_response)`

中间件工厂必须接受 `get_response` 参数。还可以初始化中间件的一些全局状态。记住两个注意事项：

- Django仅用 `get_response` 参数初始化您的中间件，因此不能定义 `__init__()` ，因为需要其他参数。
- 与每次请求调用 `__call__()` 方法不同，当 Web 服务器启动时，`__init__()` 只被称为\*一次\*。

### 标记未使用的中间件

在启动时确定是否应该使用一个中间件有时是有用的。在这些情况下，您的中间件的 `__init__()` 方法可能会引发 [`MiddlewareNotUsed`](/zh-hans/2.1/ref/exceptions/#django.core.exceptions.MiddlewareNotUsed)。Django 将从中间件进程中删除该中间件，并将调试消息记录到 [django.request](/zh-hans/2.1/topics/logging/#django-request-logger) 日志：设置 [`DEBUG`](/zh-hans/2.1/ref/settings/#std-setting-DEBUG) 为 `True`。

## 激活中间件

若要激活中间件组件，请将其添加到 Django 设置中的 [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) 列表中。

在 [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) 中，每个中间件组件由字符串表示：指向中间件工厂的类或函数名的完整 Python 路径。例如，这里创建的默认值是 [`django-admin startproject`](/zh-hans/2.1/ref/django-admin/#django-admin-startproject)：

```
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```

Django 安装不需要任何中间件——如果您愿意的话，[`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) 可以为空——但是强烈建议您至少使用 [`CommonMiddleware`](/zh-hans/2.1/ref/middleware/#django.middleware.common.CommonMiddleware)。

[`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) 的顺序很重要，因为中间件会依赖其他中间件。例如：类 [`AuthenticationMiddleware`](/zh-hans/2.1/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware) 在会话中存储经过身份验证的用户；因此，它必须在 [`SessionMiddleware`](/zh-hans/2.1/ref/middleware/#django.contrib.sessions.middleware.SessionMiddleware) 后面运行 。中间件。Session中间件。请参阅 [Middleware ordering](/zh-hans/2.1/ref/middleware/#middleware-ordering) ，用于一些关于 Django 中间件类排序的常见提示。

## 中间件顺序与分层

在请求阶段，在调用视图之前，Django 按照定义的顺序应用中间件 [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE)，自顶向下。

你可以把它想象成一个洋葱：每个中间件类都是一个“层”，它覆盖了洋葱的核心。如果请求通过洋葱的所有层（每一个调用 `get_response` ）以将请求传递到下一层，一直到内核的视图，那么响应将在返回的过程中通过每个层（以相反的顺序）。

If one of the layers decides to short-circuit and return a response without
ever calling its `get_response`, none of the layers of the onion inside that
layer (including the view) will see the request or the response. The response
will only return through the same layers that the request passed in through.

## Other middleware hooks

Besides the basic request/response middleware pattern described earlier, you
can add three other special methods to class-based middleware:

### `process_view()`

#### `process_view(request, view_func, view_args, view_kwargs)`

`request` is an [`HttpRequest`](/zh-hans/2.1/ref/request-response/#django.http.HttpRequest) object. `view_func` is
the Python function that Django is about to use. (It's the actual function
object, not the name of the function as a string.) `view_args` is a list of
positional arguments that will be passed to the view, and `view_kwargs` is a
dictionary of keyword arguments that will be passed to the view. Neither
`view_args` nor `view_kwargs` include the first view argument
(`request`).

`process_view()` is called just before Django calls the view.

It should return either `None` or an [`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse)
object. If it returns `None`, Django will continue processing this request,
executing any other `process_view()` middleware and, then, the appropriate
view. If it returns an [`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse) object, Django won't
bother calling the appropriate view; it'll apply response middleware to that
[`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse) and return the result.

> **Note**
>
> Accessing [`request.POST`](/zh-hans/2.1/ref/request-response/#django.http.HttpRequest.POST) inside
> middleware before the view runs or in `process_view()` will prevent any
> view running after the middleware from being able to [modify the
> upload handlers for the request](/zh-hans/2.1/topics/http/file-uploads/#modifying-upload-handlers-on-the-fly),
> and should normally be avoided.
>
> The [`CsrfViewMiddleware`](/zh-hans/2.1/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware) class can be
> considered an exception, as it provides the
> [`csrf_exempt()`](/zh-hans/2.1/ref/csrf/#django.views.decorators.csrf.csrf_exempt) and
> [`csrf_protect()`](/zh-hans/2.1/ref/csrf/#django.views.decorators.csrf.csrf_protect) decorators which allow
> views to explicitly control at what point the CSRF validation should occur.

### `process_exception()`

#### `process_exception(request, exception)`

`request` is an [`HttpRequest`](/zh-hans/2.1/ref/request-response/#django.http.HttpRequest) object. `exception` is an
`Exception` object raised by the view function.

Django calls `process_exception()` when a view raises an exception.
`process_exception()` should return either `None` or an
[`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse) object. If it returns an
[`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse) object, the template response and response
middleware will be applied and the resulting response returned to the
browser. Otherwise, [default exception handling](/zh-hans/2.1/ref/views/#error-views) kicks in.

Again, middleware are run in reverse order during the response phase, which
includes `process_exception`. If an exception middleware returns a response,
the `process_exception` methods of the middleware classes above that
middleware won't be called at all.

### `process_template_response()`

#### `process_template_response(request, response)`

`request` is an [`HttpRequest`](/zh-hans/2.1/ref/request-response/#django.http.HttpRequest) object. `response` is
the [`TemplateResponse`](/zh-hans/2.1/ref/template-response/#django.template.response.TemplateResponse) object (or equivalent)
returned by a Django view or by a middleware.

`process_template_response()` is called just after the view has finished
executing, if the response instance has a `render()` method, indicating that
it is a [`TemplateResponse`](/zh-hans/2.1/ref/template-response/#django.template.response.TemplateResponse) or equivalent.

It must return a response object that implements a `render` method. It could
alter the given `response` by changing `response.template_name` and
`response.context_data`, or it could create and return a brand-new
[`TemplateResponse`](/zh-hans/2.1/ref/template-response/#django.template.response.TemplateResponse) or equivalent.

You don't need to explicitly render responses -- responses will be
automatically rendered once all template response middleware has been
called.

Middleware are run in reverse order during the response phase, which
includes `process_template_response()`.

## Dealing with streaming responses

Unlike [`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse),
[`StreamingHttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.StreamingHttpResponse) does not have a `content`
attribute. As a result, middleware can no longer assume that all responses
will have a `content` attribute. If they need access to the content, they
must test for streaming responses and adjust their behavior accordingly:

```
if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)
```

> **Note**
>
> `streaming_content` should be assumed to be too large to hold in memory.
> Response middleware may wrap it in a new generator, but must not consume
> it. Wrapping is typically implemented as follows:
>
> ```
> def wrap_streaming_content(content):
>     for chunk in content:
>         yield alter_content(chunk)
> ```

## 异常处理

Django automatically converts exceptions raised by the view or by middleware
into an appropriate HTTP response with an error status code. [Certain
exceptions](/zh-hans/2.1/ref/views/#error-views) are converted to 4xx status codes, while an unknown
exception is converted to a 500 status code.

This conversion takes place before and after each middleware (you can think of
it as the thin film in between each layer of the onion), so that every
middleware can always rely on getting some kind of HTTP response back from
calling its `get_response` callable. Middleware don't need to worry about
wrapping their call to `get_response` in a `try/except` and handling an
exception that might have been raised by a later middleware or the view. Even
if the very next middleware in the chain raises an
[`Http404`](/zh-hans/2.1/topics/http/views/#django.http.Http404) exception, for example, your middleware won't see
that exception; instead it will get an [`HttpResponse`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse)
object with a [`status_code`](/zh-hans/2.1/ref/request-response/#django.http.HttpResponse.status_code) of 404.

## Upgrading pre-Django 1.10-style middleware

#### `class django.utils.deprecation.MiddlewareMixin`

Django provides `django.utils.deprecation.MiddlewareMixin` to ease creating
middleware classes that are compatible with both [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) and the
old `MIDDLEWARE_CLASSES`. All middleware classes included with Django
are compatible with both settings.

The mixin provides an `__init__()` method that accepts an optional
`get_response` argument and stores it in `self.get_response`.

The `__call__()` method:

1. Calls `self.process_request(request)` (if defined).
2. Calls `self.get_response(request)` to get the response from later
   middleware and the view.
3. Calls `self.process_response(request, response)` (if defined).
4. Returns the response.

If used with `MIDDLEWARE_CLASSES`, the `__call__()` method will
never be used; Django calls `process_request()` and `process_response()`
directly.

In most cases, inheriting from this mixin will be sufficient to make an
old-style middleware compatible with the new system with sufficient
backwards-compatibility. The new short-circuiting semantics will be harmless or
even beneficial to the existing middleware. In a few cases, a middleware class
may need some changes to adjust to the new semantics.

These are the behavioral differences between using [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) and
`MIDDLEWARE_CLASSES`:

1. Under `MIDDLEWARE_CLASSES`, every middleware will always have its
   `process_response` method called, even if an earlier middleware
   short-circuited by returning a response from its `process_request`
   method. Under [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE), middleware behaves more like an onion:
   the layers that a response goes through on the way out are the same layers
   that saw the request on the way in. If a middleware short-circuits, only
   that middleware and the ones before it in [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE) will see the
   response.
2. Under `MIDDLEWARE_CLASSES`, `process_exception` is applied to
   exceptions raised from a middleware `process_request` method. Under
   [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE), `process_exception` applies only to exceptions
   raised from the view (or from the `render` method of a
   [`TemplateResponse`](/zh-hans/2.1/ref/template-response/#django.template.response.TemplateResponse)). Exceptions raised from
   a middleware are converted to the appropriate HTTP response and then passed
   to the next middleware.
3. Under `MIDDLEWARE_CLASSES`, if a `process_response` method raises
   an exception, the `process_response` methods of all earlier middleware are
   skipped and a `500 Internal Server Error` HTTP response is always
   returned (even if the exception raised was e.g. an
   [`Http404`](/zh-hans/2.1/topics/http/views/#django.http.Http404)). Under [`MIDDLEWARE`](/zh-hans/2.1/ref/settings/#std-setting-MIDDLEWARE), an exception
   raised from a middleware will immediately be converted to the appropriate
   HTTP response, and then the next middleware in line will see that
   response. Middleware are never skipped due to a middleware raising an
   exception.
