========== Middleware中间件 ========== 中间件是一个钩子框架,介入到Django的request和response的处理过程中。它是一个 轻量级,低级别的“插件”系统,用于全局的处理Django的输入和(或)输出。 每个中间件组件都是用来完成一些特殊的功能。比如,Django中的一个中间件组建, ``XViewMiddleware`` ,它的功能是给每个HEAD请求的响应增加一个 ``"X-View"`` 的HTTP头部。 这篇文档讲解了中间件是如何工作的,如何开启中间件,以及如何编写你自己的中间件。 Django附带一些内置的中间件可以使用开箱即用的,它们被归档在这里: :doc:`内置中 间件参考 ` 。 开启中间件 ===================== 要开启一个中间件组件,你需要把它添加到你Django settings文件中的 `MIDDLEWARE_CLASSES` 列表中。在这个列表中,每一个中间件组件用字符串的方式描述:一个完整的Python全路径加上 类的名称。比如,这是默认的中间件,在你用 :djadmin:`django-admin.py startproject `:: 创建工程的时候自动生成的 :: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ) 在request处理的期间 (:meth:`process_request` and :meth:`process_view` middleware),Django按照中间件在 :settings:`MIDDLEWARE_CLASSES` 的配置,自上 而下的应用中间件。在一个响应的处理期间 (:meth:`process_response` 和 :meth:`process_exception` 中间件) ,这些中间件类会以相反的顺序被执行,自下 而上。你可以想象它就像洋葱:每个中间件都是包在view上的一层皮: .. image:: _images/middleware.png :width: 502 :height: 417 :alt: Middleware application order. 一个Django的程序中中间件不是必需的 --比如,只要你喜欢 :setting:`MIDDLEWARE_CLASSES` 可以是空的,-- 但是强烈推荐你至少使用 :class:`~django.middleware.common.CommonMiddleware` 。 编写你自己的中间件 =========================== 编写自己的中间件是很容易的。每个中间件都是一个单独的Python的class,你可以定义 一个或多个下面的这些方法: .. _request-middleware: ``process_request`` ------------------- .. method:: process_request(self, request) ``request`` 是一个 :class:`~django.http.HttpRequest` 对象. 这个方法会被 每次请求调用, 在Django决定哪个视图(view)被执行之前。 ``process_request()`` 应该返回一个 ``None`` 或者一个 :class:`~django.http.HttpResponse` 对象. 如果返回一个 ``None``,Django将会继续 处理这个请求,执行其他的middleware并且,然后,显示对应的视图。如果它返回一个 :class:`~django.http.HttpResponse` 对象,Django便不再会去调用其他的处理 request,view或者exception的middleware(中间件),或者对应的视图;它会返回 :class:`~django.http.HttpResponse`。处理Response(响应)的middleware会处理任何 返回的response(响应)。 .. _view-middleware: ``process_view`` ---------------- .. method:: process_view(self, request, view_func, view_args, view_kwargs) ``request`` 是一个 :class:`~django.http.HttpRequest` 对象。 ``view_func`` 是 Django将会调用的一个Python的方法。(它确实是一个方法对象,而不是仅仅是以方法 的字符串命名。) ``view_args`` 是一个会被传递到视图中的位置参数的列表, ``view_kwargs`` 是一个将会被传递到视图中的关键字参数字典。 ``view_args`` 和 ``view_kwargs`` 中都不包含视图的第一个参数(``request``)。 ``process_view()`` 会在Django调用视图(view)之前被调用。它应该返回一个 ``None`` 或者一个 :class:`~django.http.HttpResponse` 对象。如果它返回 ``None`` ,Django 将会继续处理这个请求,执行其他的 ``process_view()`` 中间件,然后,显示对应的视 图。如果它返回一个 :class:`~django.http.HttpResponse` 对象,Django便不再会去调 用其他的处理request,view或者exception的middleware(中间件),或者对应的视图;它会 返回 :class:`~django.http.HttpResponse`。处理Response(响应)的middleware会处理任何 返回的response(响应)。 .. 注意:: 在中间件内部,从 ``process_request`` 或者 ``process_view`` 方法中访问 :attr:`request.POST ` 或者 :attr:`request.REQUEST ` 将会阻碍该中间 件之后的所有视图无法 :ref:`修改request的上传处理程序 ` , 一般情况要避免这样使用。 类 :class:`~django.middleware.csrf.CsrfViewMiddleware` 可以被认为是个例外 ,因为它提供了 :func:`~django.views.decorators.csrf.csrf_exempt` 和 :func:`~django.views.decorators.csrf.csrf_protect` 两个允许视图来精确控制 在哪个点需要开启CSRF验证。 .. _template-response-middleware: ``process_template_response`` ----------------------------- .. versionadded:: 1.3 .. method:: process_template_response(self, request, response) ``request`` 是一个 :class:`~django.http.HttpRequest` 对象. ``response`` 是 :class:`~django.template.response.SimpleTemplateResponse` 的一个子类 (例如. :class:`~django.template.response.TemplateResponse`) 或者说任何一个response 对象都要实现一个 ``render`` 方法。 ``process_template_response()`` 必须返回一个实现redner方法的response对象。 它可以修改给定的 ``response`` 对象,通过修改 ``response.template_name`` 和 ``response.context_data`` 或者它可以创建一个全新的 :class:`~django.template.response.SimpleTemplateResponse` 或等价的对象。 只有当response实例拥有 ``render()`` 方法时 ``process_template_response()`` 才会被调用,这表明它是一个 :class:`~django.template.response.TemplateResponse` 类型或者等价类型. 你不需要显式的渲染responses -- 一旦所有的模板响应中间件被调用,responses会自动 的被渲染。 在一个响应的处理期间中间件被以相反的顺序运行,这包括 process_template_response Middleware are run in reverse order during the response phase, which includes process_template_response. .. _response-middleware: ``process_response`` -------------------- .. method:: process_response(self, request, response) ``request`` 是一个 :class:`~django.http.HttpRequest` 对象。 ``response`` 是 被Django的view返回的一个:class:`~django.http.HttpResponse` 对象。 ``process_response()`` 必须返回一个 :class:`~django.http.HttpResponse` 对象。 它可以修改已有的 ``response``, 或者创建并返回一个全新的 :class:`~django.http.HttpResponse`. 不像 ``process_request()`` 和 ``process_view()`` 方法, ``process_response()`` 方法总是会被调用, 即使同一个中间件类中的 ``process_request()`` 和 ``process_view()`` 方法会因为前面的一个中间件返回 :class:`~django.http.HttpResponse` 而被跳过。 (这意味着你的 ``process_response()`` 方法不能依赖于 ``process_request()`` 方法中 的设置,比如)。此外,在一个响应的处理期间,那些类也是以相反的顺序被使用,自下而上的。 这说明在在 :setting:`MIDDLEWARE_CLASSES` 最后的类型被先被执行。 .. _exception-middleware: ``process_exception`` --------------------- .. method:: process_exception(self, request, exception) ``request`` 是一个 :class:`~django.http.HttpRequest` 对象。 ``exception``是一 个被视图中的方法抛出来的 ``Exception`` 对象。 当一个视图抛出异常时,Django会调用 ``process_exception`` 来处理。 同样,``process_exception()`` 应该返回一个 ``None`` 或者一个 :class:`~django.http.HttpResponse` 对象。 如果它返回一个 :class:`~django.http.HttpResponse` 对象,这个response将会直接返回给浏览器。 否则,默认的异常处理器就开始起作用了。 再次提醒,在处理response期间,中间件的执行顺序是倒序执行的,这包括 ``process_exception`` 。如果一个异常处理的中间件返回了一个response,那这个中间件上面的中间件都将不会 被调用。 ``__init__`` ------------ 大多数的中间件类都不需要一个初始化方法,因为中间件的类定义仅仅是为 ``process_*`` 提供一个占位符。如果你确实需要一个全局的状态那就可以通过 ``__init__`` 来加载。然后要铭记如下两个警告: * Django初始化你的中间件无需任何参数,因此不要定义一个有参数的 ``__init__`` 方法. * 不像 ``process_*`` 这种每个request请求过来都要调用的方法一样, ``__init__`` 只会被调用 *一次* ,就是在Web服务启动的时候。 标记中间件不被使用 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 有时在运行时决定是否一个中间件需要被加载是很有用的。在这种情况下,你的中间件 中的 ``__init__`` 方法可以抛出一个 ``django.core.exceptions.MiddlewareNotUsed``异常。这样Django就会从中间件的 处理过程中移除这部分中间件。 指导准则 ---------- * 中间件的类不能是任何类的子类 * 中间件可以存在与你Python路径中的任何位置。Django所关心的只是被包含在 :setting:`MIDDLEWARE_CLASSES` 中的配置。 * 把 :doc:`Django's available middleware ` 当做例子随便 看看。 * 如果你认为你写的中间件组建可能会对比人有用,那就把它共享到社区! :doc:`Let us know `, 并且我们会考虑把 它添加到Django中。