{"title":"中间件","version":"5.0","locale":"zh-hans","docname":"topics/http/middleware","url":"/zh-hans/5.0/topics/http/middleware/","canonical":"https://djangodocs.dev/zh-hans/5.0/topics/http/middleware/","summary":"中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统，用于全局改变 Django 的输入或输出。 每个中间件组件负责做一些特定的功能。例如，Django 包含一个中间件组件 AuthenticationMiddleware ，它使用会话将用户与请求关联起来。…","html":"<h1>中间件<a class=\"heading-anchor\" href=\"#middleware\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统，用于全局改变 Django 的输入或输出。</p>\n<p>每个中间件组件负责做一些特定的功能。例如，Django 包含一个中间件组件 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware\" title=\"django.contrib.auth.middleware.AuthenticationMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AuthenticationMiddleware</span></code></a>，它使用会话将用户与请求关联起来。</p>\n<p>他的文档解释了中间件是如何工作的，如何激活中间件，以及如何编写自己的中间件。Django 具有一些内置的中间件，你可以直接使用。它们被记录在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/\"><span class=\"doc\">built-in middleware reference</span></a> 中。</p>\n<section id=\"writing-your-own-middleware\">\n<h2>编写自己的中间件<a class=\"heading-anchor\" href=\"#writing-your-own-middleware\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>中间件工厂是一个可调用的程序，它接受 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 可调用并返回中间件。中间件是可调用的，它接受请求并返回响应，就像视图一样。</p>\n<p>中间件可以被写成这样的函数：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">simple_middleware</span><span class=\"p\">(</span><span class=\"n\">get_response</span><span class=\"p\">):</span>\n    <span class=\"c1\"># One-time configuration and initialization.</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">middleware</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Code to be executed for each request before</span>\n        <span class=\"c1\"># the view (and later middleware) are called.</span>\n\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">get_response</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Code to be executed for each request/response after</span>\n        <span class=\"c1\"># the view is called.</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">response</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">middleware</span>\n</code></pre></div>\n<p>或者它可以写成一个类，它的实例是可调用的，如下：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">SimpleMiddleware</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">get_response</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_response</span> <span class=\"o\">=</span> <span class=\"n\">get_response</span>\n        <span class=\"c1\"># One-time configuration and initialization.</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__call__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Code to be executed for each request before</span>\n        <span class=\"c1\"># the view (and later middleware) are called.</span>\n\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_response</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Code to be executed for each request/response after</span>\n        <span class=\"c1\"># the view is called.</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n<p>Django 提供的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 响应可能是实际视图（如果这是最后列出的中间件），或者它可能是链中的下一个中间件。不需要知道或关心当前的中间件到底是什么，它只是代表了下一步的内容。</p>\n<p>以上是一个轻微的简化——链中最后一个中间件调用的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 可不是实际视图，而是处理程序的包装方法，它负责应用 <a class=\"reference internal\" href=\"#view-middleware\"><span class=\"std std-ref\">view middleware</span></a>，调用具有适当URL参数的视图，并应用 <a class=\"reference internal\" href=\"#template-response-middleware\"><span class=\"std std-ref\">template-response</span></a> 和 <a class=\"reference internal\" href=\"#exception-middleware\"><span class=\"std std-ref\">exception</span></a> 中间件。</p>\n<p>中间件可以只支持同步Python(默认)，或异步Python，或者二者都支持。查看 <a class=\"reference internal\" href=\"#async-middleware\"><span class=\"std std-ref\">异步支持</span></a> 来了解如何通知你支持的是什么以及如何知道你是哪种请求。</p>\n<p>中间件可以放在 Python 路径上的任何地方。</p>\n<section id=\"init-get-response\">\n<h3><code class=\"docutils literal notranslate\"><span class=\"pre\">__init__(get_response)</span></code><a class=\"heading-anchor\" href=\"#init-get-response\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>中间件工厂必须接受 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 参数。还可以初始化中间件的一些全局状态。记住两个注意事项：</p>\n<ul class=\"simple\">\n<li><p>Django仅用 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 参数初始化您的中间件，因此不能定义 <code class=\"docutils literal notranslate\"><span class=\"pre\">__init__()</span></code> ，因为需要其他参数。</p></li>\n<li><p>与每个请求调用一次的 <code class=\"docutils literal notranslate\"><span class=\"pre\">__call__()</span></code> 方法不同，<code class=\"docutils literal notranslate\"><span class=\"pre\">__init__()</span></code> 方法只在 Web 服务器启动时调用一次。</p></li>\n</ul>\n</section>\n<section id=\"marking-middleware-as-unused\">\n<h3>标记未使用的中间件<a class=\"heading-anchor\" href=\"#marking-middleware-as-unused\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在启动时确定是否应该使用一个中间件有时是有用的。在这些情况下，您的中间件的 <code class=\"docutils literal notranslate\"><span class=\"pre\">__init__()</span></code> 方法可能会引发 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/exceptions/#django.core.exceptions.MiddlewareNotUsed\" title=\"django.core.exceptions.MiddlewareNotUsed\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">MiddlewareNotUsed</span></code></a>。Django 将从中间件进程中删除该中间件，并将调试消息记录到 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/logging/#django-request-logger\"><span class=\"std std-ref\">django.request</span></a> 日志：设置 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DEBUG</span></code></a> 为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>。</p>\n</section>\n</section>\n<section id=\"activating-middleware\">\n<h2>激活中间件<a class=\"heading-anchor\" href=\"#activating-middleware\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>若要激活中间件组件，请将其添加到 Django 设置中的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 列表中。</p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 中，每个中间件组件由字符串表示：指向中间件工厂的类或函数名的完整 Python 路径。例如，这里创建的默认值是 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">django-admin</span> <span class=\"pre\">startproject</span></code></a>：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">MIDDLEWARE</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.middleware.security.SecurityMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.sessions.middleware.SessionMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.middleware.common.CommonMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.middleware.csrf.CsrfViewMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.middleware.AuthenticationMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.messages.middleware.MessageMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.middleware.clickjacking.XFrameOptionsMiddleware&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Django 安装不需要任何中间件——如果您愿意的话，<a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 可以为空——但是强烈建议您至少使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#django.middleware.common.CommonMiddleware\" title=\"django.middleware.common.CommonMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CommonMiddleware</span></code></a>。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 的顺序很重要，因为中间件会依赖其他中间件。例如：类 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware\" title=\"django.contrib.auth.middleware.AuthenticationMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AuthenticationMiddleware</span></code></a> 在会话中存储经过身份验证的用户；因此，它必须在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#django.contrib.sessions.middleware.SessionMiddleware\" title=\"django.contrib.sessions.middleware.SessionMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">SessionMiddleware</span></code></a> 后面运行 。中间件。Session中间件。请参阅 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#middleware-ordering\"><span class=\"std std-ref\">中间件顺序</span></a> ，用于一些关于 Django 中间件类排序的常见提示。</p>\n</section>\n<section id=\"middleware-order-and-layering\">\n<h2>中间件顺序与分层<a class=\"heading-anchor\" href=\"#middleware-order-and-layering\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>在请求阶段，在调用视图之前，Django 按照定义的顺序应用中间件 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a>，自顶向下。</p>\n<p>你可以把它想象成一个洋葱：每个中间件类都是一个“层”，它覆盖了洋葱的核心。如果请求通过洋葱的所有层（每一个调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> ）以将请求传递到下一层，一直到内核的视图，那么响应将在返回的过程中通过每个层（以相反的顺序）。</p>\n<p>如果其中一层决定停止并返回响应而不调用get_response，那么该层(包括视图)中的洋葱层都不会看到请求或响应。响应将只通过请求传入的相同层返回。</p>\n</section>\n<section id=\"other-middleware-hooks\">\n<h2>其他中间件钩子<a class=\"heading-anchor\" href=\"#other-middleware-hooks\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>除前面说书的基础请求/响应中间件模式外，你可以给基于类的中间件添加三种其他特殊方法：</p>\n<section id=\"process-view\">\n<span id=\"view-middleware\"></span><h3><code class=\"docutils literal notranslate\"><span class=\"pre\">process_view()</span></code><a class=\"heading-anchor\" href=\"#process-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"process_view\">\n<span class=\"sig-name descname\"><span class=\"pre\">process_view</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">view_func</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">view_args</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">view_kwargs</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#process_view\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 是一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 对象。<code class=\"docutils literal notranslate\"><span class=\"pre\">view_func</span></code> 是一个 Django 将要使用的 Python 函数。（这是一个真实的函数对象，不是函数的名称）；<code class=\"docutils literal notranslate\"><span class=\"pre\">view_args</span></code> 是一个用来传递给视图的位置参数列表，；<code class=\"docutils literal notranslate\"><span class=\"pre\">view_kwargs</span></code> 是一个用来传递给视图的关键字参数字典。<code class=\"docutils literal notranslate\"><span class=\"pre\">view_args</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">view_kwargs</span></code> 都不包含第一个视图参数 ( <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> )。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">process_view()</span></code> 只在 Django 调用视图前被调用。</p>\n<p>它应该返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> 或 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象。如果它返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> ，Django 将继续处理这个请求，执行任何其他的 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_view()</span></code> ，然后执行相应的视图。如果它返回 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象，Django 不会去影响调用相应的视图；它会将响应中间件应用到 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 并返回结果。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>在视图运行前或在 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_view()</span></code> 内访问中间件里的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> 将阻止中间件之后运行的任何视图修改请求的上传处理程序 （<a class=\"reference internal\" href=\"/zh-hans/5.0/topics/http/file-uploads/#modifying-upload-handlers-on-the-fly\"><span class=\"std std-ref\">modify the upload handlers for the request</span></a>  ），通常应该避免这样。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware\" title=\"django.middleware.csrf.CsrfViewMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CsrfViewMiddleware</span></code></a> 类可以被视为一个例外，因为它提供 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/csrf/#django.views.decorators.csrf.csrf_exempt\" title=\"django.views.decorators.csrf.csrf_exempt\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csrf_exempt()</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/csrf/#django.views.decorators.csrf.csrf_protect\" title=\"django.views.decorators.csrf.csrf_protect\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csrf_protect()</span></code></a> 装饰器，它们允许视图完全控制 CSRF 验证在什么时候进行。</p>\n</aside>\n</section>\n<section id=\"process-exception\">\n<span id=\"exception-middleware\"></span><h3><code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception()</span></code><a class=\"heading-anchor\" href=\"#process-exception\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"process_exception\">\n<span class=\"sig-name descname\"><span class=\"pre\">process_exception</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">exception</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#process_exception\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 是一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 对象。 <code class=\"docutils literal notranslate\"><span class=\"pre\">exception</span></code> 是一个由视图函数引发的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Exception</span></code> 对象。</p>\n<p>当视图引发异常时，Django 会调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception()</span></code>。<code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception()</span></code> 应该返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> 或 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象。如果它返回一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象，模板响应和响应中间件将被应用且会将结果响应返回浏览器。否则，就会开始默认异常处理（ <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/views/#error-views\"><span class=\"std std-ref\">default exception handling</span></a> ）。</p>\n<p>再次，中间件在响应阶段会按照相反的顺序运行，其中包括 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception</span></code> 。如果异常中间件返回一个响应，那么中间件之上的中间件类的 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception</span></code> 方法根本不会被调用。</p>\n</section>\n<section id=\"process-template-response\">\n<span id=\"template-response-middleware\"></span><h3><code class=\"docutils literal notranslate\"><span class=\"pre\">process_template_response()</span></code><a class=\"heading-anchor\" href=\"#process-template-response\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"process_template_response\">\n<span class=\"sig-name descname\"><span class=\"pre\">process_template_response</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">response</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#process_template_response\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 是一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 对象。<code class=\"docutils literal notranslate\"><span class=\"pre\">response</span></code> 是 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/template-response/#django.template.response.TemplateResponse\" title=\"django.template.response.TemplateResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponse</span></code></a> 对象（或者等效对象），它通过 Django 视图或中间件返回。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">process_template_response()</span></code> 在视图被完全执行后调用，如果响应实例有 <code class=\"docutils literal notranslate\"><span class=\"pre\">render()</span></code> 方法，表明它是一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/template-response/#django.template.response.TemplateResponse\" title=\"django.template.response.TemplateResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponse</span></code></a> 或等效对象。</p>\n<p>它必须返回一个实现了 <code class=\"docutils literal notranslate\"><span class=\"pre\">render</span></code> 方法的响应对象。它可以通过改变``response.template_name`` 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">response.context_data</span></code> 来改变给定的 <code class=\"docutils literal notranslate\"><span class=\"pre\">response</span></code> ，或者它可以创建和返回全新的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/template-response/#django.template.response.TemplateResponse\" title=\"django.template.response.TemplateResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponse</span></code></a> 或等效对象。</p>\n<p>你不需要显式地渲染响应——一旦所有模板中间件被调用，响应会被自动渲染。</p>\n<p>中间件会在响应阶段按照相反的顺序运行，其中包括 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_template_response()</span></code> 。</p>\n</section>\n</section>\n<section id=\"dealing-with-streaming-responses\">\n<h2>处理流式响应<a class=\"heading-anchor\" href=\"#dealing-with-streaming-responses\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>与 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 不同，<a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.StreamingHttpResponse\" title=\"django.http.StreamingHttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">StreamingHttpResponse</span></code></a> 没有 <code class=\"docutils literal notranslate\"><span class=\"pre\">content</span></code> 属性。因此，中间件不能再假设所有响应有 <code class=\"docutils literal notranslate\"><span class=\"pre\">content</span></code> 属性。如果它们需要访问 content，它们必须为流式响应进行测试，并且调整其行为：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">if</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">streaming</span><span class=\"p\">:</span>\n    <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">streaming_content</span> <span class=\"o\">=</span> <span class=\"n\">wrap_streaming_content</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">streaming_content</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">content</span> <span class=\"o\">=</span> <span class=\"n\">alter_content</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">content</span><span class=\"p\">)</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">streaming_content</span></code> 被假设为体积太大而无法在内存中保存。响应中间件可以将其包装在一个新的生成器里，但不能使用它。包装通常如下实现：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">wrap_streaming_content</span><span class=\"p\">(</span><span class=\"n\">content</span><span class=\"p\">):</span>\n    <span class=\"k\">for</span> <span class=\"n\">chunk</span> <span class=\"ow\">in</span> <span class=\"n\">content</span><span class=\"p\">:</span>\n        <span class=\"k\">yield</span> <span class=\"n\">alter_content</span><span class=\"p\">(</span><span class=\"n\">chunk</span><span class=\"p\">)</span>\n</code></pre></div>\n</aside>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.StreamingHttpResponse\" title=\"django.http.StreamingHttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">StreamingHttpResponse</span></code></a> 允许同步和异步迭代器。包装函数必须匹配。如果你的中间件需要支持两种类型的迭代器，请检查 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.StreamingHttpResponse.is_async\" title=\"django.http.StreamingHttpResponse.is_async\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">StreamingHttpResponse.is_async</span></code></a>。</p>\n<aside class=\"version-note version-changed\" data-version=\"4.2\">\n<p class=\"version-note-title\">Changed in Django 4.2</p><p>支持使用异步迭代器的流式响应已经添加。</p>\n</aside>\n</section>\n<section id=\"exception-handling\">\n<h2>异常处理<a class=\"heading-anchor\" href=\"#exception-handling\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 自动转换视图引发的异常，或者带有错误状态代码的特定 HTTP 响应内的中间件引发的异常。某些异常（ <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/views/#error-views\"><span class=\"std std-ref\">Certain exceptions</span></a> ）被转换为 4xx 状态代码，而未知异常被转换为 500 状态代码。</p>\n<p>这个变换发生在每个中间件的前后（你可以把它想象成洋葱每层中间的薄膜），因此每个中间件总是可以依赖于从调用它的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 回调中获得某种类型的HTTP响应。中间件不需要担心它们对 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 的调用包装在 <code class=\"docutils literal notranslate\"><span class=\"pre\">try/except</span></code> 里，也不需要担心处理稍后的中间件或视图引发的异常。即使链中的下一个中间件引发了 <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Http404</span></code></a> 异常，比如中间件不会查看异常，相反，它会得到一个带有404 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse.status_code\" title=\"django.http.HttpResponse.status_code\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">status_code</span></code></a> 的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象。</p>\n<p>你可以将 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-DEBUG_PROPAGATE_EXCEPTIONS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DEBUG_PROPAGATE_EXCEPTIONS</span></code></a> 设置为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 来跳过这个转换并将异常传播到上层。</p>\n</section>\n<section id=\"asynchronous-support\">\n<span id=\"async-middleware\"></span><h2>异步支持<a class=\"heading-anchor\" href=\"#asynchronous-support\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>中间件支持同步和异步请求的任意组合。如果Django不能同时支持它们，它会调整请求来适应中间件的需求，但会有性能损失。</p>\n<p>默认情况下，Django假设你的中间件只能处理同步请求。如果要改变这种模式，需要在你的中间件工厂函数或类中添加入如下属性：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">sync_capable</span></code> 是一个布尔值，来表明中间件是否处理同步请求。默认为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">async_capable</span></code> 是一个布尔值，来表明中间件是否处理异步请求。默认为 <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>。</p></li>\n</ul>\n<p>如果你的中间件同时设置了 <code class=\"docutils literal notranslate\"><span class=\"pre\">sync_capable</span> <span class=\"pre\">=</span> <span class=\"pre\">True</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">async_capable</span> <span class=\"pre\">=</span> <span class=\"pre\">True</span></code>，那么Django将直接传递请求而不进行转换。在这种情况下，你可以通过检查传递给你的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 对象是否是协程函数，使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">asgiref.sync.iscoroutinefunction</span></code> 来确定你的中间件是否会接收到异步请求。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">django.utils.decorators</span></code> 模块包含 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/utils/#django.utils.decorators.sync_only_middleware\" title=\"django.utils.decorators.sync_only_middleware\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_only_middleware()</span></code></a>，<a class=\"reference internal\" href=\"/zh-hans/5.0/ref/utils/#django.utils.decorators.async_only_middleware\" title=\"django.utils.decorators.async_only_middleware\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_only_middleware()</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/utils/#django.utils.decorators.sync_and_async_middleware\" title=\"django.utils.decorators.sync_and_async_middleware\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_and_async_middleware()</span></code></a> 装饰器，允许你将这些标志应用到中间件工厂函数中。</p>\n<p>返回的可调用对象必须符合 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 方法的同步或异步性质。如果你有一个异步的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code>，你必须返回一个协程函数（<code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">def</span></code>）。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">process_view</span></code>、<code class=\"docutils literal notranslate\"><span class=\"pre\">process_template_response</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception</span></code> 方法，如果有的话，也应该进行调整以匹配同步／异步模式。然而，如果你不这样做，Django 会根据需要单独调整它们，但会有额外的性能损失。</p>\n<p>下面以一个例子来说明如何创建一个支持这两种功能的中间件函数：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">asgiref.sync</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">iscoroutinefunction</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils.decorators</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">sync_and_async_middleware</span>\n\n\n<span class=\"nd\">@sync_and_async_middleware</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">simple_middleware</span><span class=\"p\">(</span><span class=\"n\">get_response</span><span class=\"p\">):</span>\n    <span class=\"c1\"># One-time configuration and initialization goes here.</span>\n    <span class=\"k\">if</span> <span class=\"n\">iscoroutinefunction</span><span class=\"p\">(</span><span class=\"n\">get_response</span><span class=\"p\">):</span>\n\n        <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">middleware</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n            <span class=\"c1\"># Do something here!</span>\n            <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"n\">get_response</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">response</span>\n\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n\n        <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">middleware</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n            <span class=\"c1\"># Do something here!</span>\n            <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">get_response</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">response</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">middleware</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>如果你声明了一个同时支持同步和异步调用的混合中间件，你得到的调用种类可能与底层视图不匹配。Django 会优化中间件调用栈，使其尽可能少的同步／异步转换。</p>\n<p>因此，即使你包装的是一个异步视图，如果在你和视图之间有其他的、同步的中间件，你也可能会在同步模式下被调用。</p>\n</aside>\n<p>在使用异步的基于类的中间件时，你必须确保实例被正确标记为协程函数：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">asgiref.sync</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">iscoroutinefunction</span><span class=\"p\">,</span> <span class=\"n\">markcoroutinefunction</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AsyncMiddleware</span><span class=\"p\">:</span>\n    <span class=\"n\">async_capable</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n    <span class=\"n\">sync_capable</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">get_response</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_response</span> <span class=\"o\">=</span> <span class=\"n\">get_response</span>\n        <span class=\"k\">if</span> <span class=\"n\">iscoroutinefunction</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_response</span><span class=\"p\">):</span>\n            <span class=\"n\">markcoroutinefunction</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n\n    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__call__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_response</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n        <span class=\"c1\"># Some logic ...</span>\n        <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n</section>\n<section id=\"upgrading-pre-django-1-10-style-middleware\">\n<span id=\"upgrading-middleware\"></span><h2>升级 Django 1.10 之前的中间件<a class=\"heading-anchor\" href=\"#upgrading-pre-django-1-10-style-middleware\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.utils.deprecation.MiddlewareMixin\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">django.utils.deprecation.</span></span><span class=\"sig-name descname\"><span class=\"pre\">MiddlewareMixin</span></span><a class=\"heading-anchor\" href=\"#django.utils.deprecation.MiddlewareMixin\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>Django 提供了 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.utils.deprecation.MiddlewareMixin</span></code> 来方便创建同时兼容 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 和旧的 <code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 的中间件类，并支持同步和异步请求。Django 所包含的所有中间件类都兼容这两种配置。</p>\n<p>mixin 提供了一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">__init__()</span></code> 方法，它需要一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_response</span></code> 参数，并将其存储在 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.get_response</span></code> 中。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">__call__()</span></code> 方法：</p>\n<ol class=\"arabic simple\">\n<li><p>调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.process_request(request)</span></code> （如果被定义过）。</p></li>\n<li><p>调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.get_response(request)</span></code> 来从后续的中间件和视图得到响应。</p></li>\n<li><p>调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.process_response(request,</span> <span class=\"pre\">response)</span></code> （如果被定义过）。</p></li>\n<li><p>返回响应。</p></li>\n</ol>\n<p>如果和 <code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 一起使用，<code class=\"docutils literal notranslate\"><span class=\"pre\">__call__()</span></code> 方法将永远不会被使用；Django 会直接调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_request()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_response()</span></code> 。</p>\n<p>在大多数情况下，从这个 Mixin 中继承就足以使一个旧式中间件与新系统兼容，并具有足够的向后兼容性。新的短路语义对现有中间件无害甚至有益。在少数情况下，中间件类可能需要一些改变来适应新的语义。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 在使用上有些行为差异：</p>\n<ol class=\"arabic simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 下，每个中间件将始终调用它的 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_response</span></code> 方法，即使早期的中间件通过从其 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_response</span></code> 方法返回响应而短路。<a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 下，中间件行为更像洋葱：响应在输出时经过的层与在输入时看到请求的层相同。如果一个中间件短路，只有那个中间件和之前的中间件可以看到响应。</p></li>\n<li><p>在 <code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 下，<code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception</span></code> 应用于中间件 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_request</span></code> 方法引发的异常。在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 下，<code class=\"docutils literal notranslate\"><span class=\"pre\">process_exception</span></code> 只应用于视图引发的异常（或者从 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/template-response/#django.template.response.TemplateResponse\" title=\"django.template.response.TemplateResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponse</span></code></a> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">render</span></code> 方法引发的异常）。中间件引发的异常被转换为合适的 HTTP 响应，然后传递到下一个中间件。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE_CLASSES</span></code> 下，如果 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_response</span></code> 方法引发了异常，所有更早之前的中间件的 <code class=\"docutils literal notranslate\"><span class=\"pre\">process_response</span></code> 方法会被跳过，并一直返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">500</span> <span class=\"pre\">Internal</span> <span class=\"pre\">Server</span> <span class=\"pre\">Error</span></code> 的 HTTP 响应（即使引发的异常是例如 <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Http404</span></code></a> ）。在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> ，一个中间件引发的异常将立刻被转换为合适的 HTTP 响应，然后下一个中间件将看到响应。中间件不会因为中间件引发异常而被跳过。</p></li>\n</ol>\n</section>","rootId":"middleware","toc":[{"title":"编写自己的中间件","anchor":"writing-your-own-middleware","children":[{"title":"__init__(get_response)","anchor":"init-get-response","children":[]},{"title":"标记未使用的中间件","anchor":"marking-middleware-as-unused","children":[]}]},{"title":"激活中间件","anchor":"activating-middleware","children":[]},{"title":"中间件顺序与分层","anchor":"middleware-order-and-layering","children":[]},{"title":"其他中间件钩子","anchor":"other-middleware-hooks","children":[{"title":"process_view()","anchor":"process-view","children":[]},{"title":"process_exception()","anchor":"process-exception","children":[]},{"title":"process_template_response()","anchor":"process-template-response","children":[]}]},{"title":"处理流式响应","anchor":"dealing-with-streaming-responses","children":[]},{"title":"异常处理","anchor":"exception-handling","children":[]},{"title":"异步支持","anchor":"asynchronous-support","children":[]},{"title":"升级 Django 1.10 之前的中间件","anchor":"upgrading-pre-django-1-10-style-middleware","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/5.0/topics/"},{"docname":"topics/http/index","title":"处理 HTTP 请求","url":"/zh-hans/5.0/topics/http/"}],"prev":{"docname":"topics/http/generic-views","title":"通用视图","url":"/zh-hans/5.0/topics/http/generic-views/"},"next":{"docname":"topics/http/sessions","title":"如何使用会话","url":"/zh-hans/5.0/topics/http/sessions/"},"formats":{"html":"/zh-hans/5.0/topics/http/middleware/","markdown":"/zh-hans/5.0/topics/http/middleware.md","json":"/zh-hans/5.0/topics/http/middleware.json"},"source":"https://github.com/django/django/blob/stable/5.0.x/docs/topics/http/middleware.txt","official":"https://docs.djangoproject.com/zh-hans/5.0/topics/http/middleware/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}