Middleware

Middleware是一个镶嵌到django的request/response处理机制中的一个hooks框架。它是一个修改django全局输入输出的一个底层插件系统。

每个中间件组件负责一些特定的功能,比如说 Django包含一个 AuthenticationMiddleware的中间间,使用sessions将用户和请求联系在一起( that associates users with requests using sessions.)。

这篇文章解释了中间件如何工作,如果激活中间件,如何编写自己的中间件。django有很多内建的中间件,详细内容查看内建中间件附录。

激活中间件

要想激活中间件,需要在settings文件中的 MIDDLEWARE_CLASSES下增加。在 MIDDLEWARE_CLASSES中,每个中间件以一个字符串的形势保存。比如,下面是默认创建工程的中间件 MIDDLEWARE_CLASSES内容:

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

一个django工程的创建不需要任何一个中间件,即如果你喜欢的话,MIDDLEWARE_CLASSES可以为空,但是强烈建议至少包含 CommonMiddleware这个中间件。
中间件在MIDDLEWARE_CLASSES中是有顺序的,因为中间件之间有相互依赖关系。比如说AuthenticationMiddleware 在session中保存认证的用户信息,因此,它必须在 SessionMiddleware之后,详细的内容可以参考Middleware ordering

Hooks和application的顺序

在请求阶段,调用views之前,django按照MIDDLEWARE_CLASSES中定义的顺序从上到下调用中间件。有两个hooks:

  • process_request()
  • process_view()

在响应阶段,调用views之后,中间件被从下到上反向调用,有三个hooks:

  • process_exception() (只有当view中raise一个例外时)
  • process_template_response() (只有view中返回template时)
  • process_response()

如果你喜欢,可以把它比作洋葱,每个中间件就是洋葱的一层皮。
每个hooks在下面描述:

编写你自己的中间件

写一个自己的中间件很简单,每个中间件就是一个普通的python类,包含下面的一个或多个方法:

1) process_request()

process_request(request)
其中request是HttpRequest对象,process_request() 将会在每个request被决定使用哪个view之前调用,它会返回None或者一个HttpResponse对象。

  • 如果返回None,django会继续执行其他中间件的process_request(), 然后是process_view() ,然后是恰当的view函数。
  • 如果返回HttpResponse对象,它就直接返回了,不再执行其他中间件,view等。

2) process_view()

process_view(request, view_func, view_args, view_kwargs)
其中request是HttpRequest 对象, view_func是django要使用的view函数 (它是实际的函数对象,而不是函数名字的字符串) view_args是view函数的列表参数, view_kwargs是view函数的字典参数。 view_args和 view_kwargs都不需要包含request这个参数。
process_view()就在django调用view函数之前被调用。
与process_request()相同,process_request()会返回None或者一个HttpResponse对象。

  • 如果返回None,django会继续执行其他中间件的process_view(),然后是恰当的view函数。
  • 如果返回HttpResponse对象,它就直接返回了,不再执行其他中间件,view等。

Note
尽量避免使用process_request 或者process_view 来访问request.POST。但是 CsrfViewMiddleware中间件是一个例外,它提供 csrf_exempt() 和 csrf_protect() 两个装饰器来解决此问题。
Accessing request.POST inside middleware from process_request orprocess_view will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided.
The CsrfViewMiddleware class can be considered an exception, as it provides the csrf_exempt() and csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should occur.

3) process_template_response()

process_template_response(request, response)
其中request 是 HttpRequest 对象, response 是一个由django view或者中间件返回的TemplateResponse 对象。
process_template_response()在view使用render渲染一个模版对象完成之后被调用,它必须返回一个render 方法执行后的response对象,它可以修改view中返回的 response.template_name 和 response.context_data,或者为view返回的模板增加一个商标等等。
你不需要明确的渲染响应,当所有的template响应中间件处理完成后会被自动渲染。
带有process_template_response()的中间件将会被自下而上反向执行。

4) process_response()

process_response(request, response)
其中request是 HttpRequest 对象, response 是一个django view或者中间件返回的 HttpResponse 或者StreamingHttpResponse对象。
process_response()在所有的响应被返回到浏览器之前执行。
必须返回一个 HttpResponse 或者StreamingHttpResponse 对象,它可以修改response, 或者为 HttpResponse 或StreamingHttpResponse增加一个商标等。
它不像 process_request() 和process_view() 方法可能会被跳过(在他之前有人返回了HttpResponse对象), process_response()方法一定会被执行。因此,你的process_response() 方法不能依赖于你的process_request()方法。
最后,记住在响应阶段,中间件会被反向执行,你最后在 MIDDLEWARE_CLASSES定义的中间件将会被最先执行。

处理流式响应

不同于HttpResponse,StreamingHttpResponse沒有content属性,因此中间件不能认为所有的响应都有content 属性,如果想要访问content,需要测试流式响应:

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

Note
streaming_content 被假定为太大而不能存放在内存中, 响应中间件可以将它包裹在一个生成器中,但是必须不能消费它,通常如下所示:

def wrap_streaming_content(content):
for chunk in content:
yield alter_content(chunk)

5) process_exception()

process_exception(request, exception)
其中request 是 HttpRequest 对象. exception是view函数中raise的Exception对象。
Django当view函数raise一个例外时调用process_exception() 。process_exception()返回None 或者HttpResponse 对象

  • 如果返回 HttpResponse 对象,template response 和response中间件会被应用, 然后在浏览器中返回结果,否则,默认的例外处理将会被使用。
    再说一遍,包含process_exception的中间件将会被反向执行,如果下面的中间件返回一个response,上面的中间间将不会被执行。

6) init()

大多数处理 process_* 方法的中间件都不需要自定义构造函数,如果你确实需要有一些全局的内容需要定义也可以使用,但是注意下面两点:

  • Django初始化中间件不会包含任何参数,所以不能在__init__ 要求任何参数;
  • 不像process_* 方法在每次请求时调用,__init__方法只会在web server首次处理请求的时候调用。

标记中间件为不可用

有时候在运行的时候决定哪个中间件是否可用是十分必要的,这种情况下你的自定义中间件__init__方法可以 raise django.core.exceptions.MiddlewareNotUsed,django将会移除中间件,并且报一个日志,如果DEBUG打开的话,可以在django.request logger里看到。(1.8之前的版本,MiddlewareNotUsed不会在日志中体现)

7)指导意见

  • 中间件不继承;
  • 中间件写在哪里都行,只需要加到MIDDLEWARE_CLASSES settings中。

来源: https://docs.djangoproject.com/en/1.9/topics/http/middleware/

django middleware介绍的更多相关文章

  1. Django Middleware简介

    1      前言 Django使用非常熟练了,各种API接口不在话下,全都搞定.为方便定位问题在每个API接口的的开始和返回的地方都加上了log打印,记录入参和返回值. 但是这样有一个问题,需要每个 ...

  2. Django框架介绍之一

    这片博文就是对django有个大概的了解,通俗的说,就是先让django跑起来. django安装 在linux上安装如下: 源码安装: tar -zxvf Django-1.9.13.tar.gz ...

  3. Django MiddleWare初识

    一.Django 中间件介绍 中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django的输入和输出.每个中间件组件都负责做一些特定 ...

  4. django框架介绍安装-自写框架

    原文链接:https://www.cnblogs.com/maple-shaw/p/8862330.html Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户 ...

  5. Django 入门介绍

    Django介绍 Django框架是PythonWeb三大主流框架之一,以其功能强大全面而受到众多开发者追捧,现如今Django已经更新到3版本,但是并不推荐使用,更多建议使用1版本. Django版 ...

  6. django中间件介绍

    在学习django中间件之前,先来认识一下django的生命周期,如下图所示: django生命周期:浏览器发送的请求会先经过wsgiref模块处理解析出request(请求数据)给到中间件,然后通过 ...

  7. Django 框架介绍

    Django 框架介绍 MVC框架和MTV框架 简单了解一下什么是MVC框架.MVC(Model View Controller),是模型(model)-视图(view)-控制器(controller ...

  8. python Django 中间件介绍

    我们一直都在使用中间件,只是没有注意到而已,打开Django项目的Settings.py文件,看到下面的MIDDLEWARE配置项,django默认自带的一些中间件: MIDDLEWARE = [ ' ...

  9. Django settings介绍

    """ Django settings for macboy project. Generated by 'django-admin startproject' usin ...

随机推荐

  1. 如何数冲突域(collision domains)个数

    数冲突域的核心是: switch.bridge的每个端口都是一个冲突域(因为它们有存储转发功能) hub的所有端口在同一冲突域内(因为hub本身是模拟导线,各个端口可以看成接在一起) 对下图而言 共有 ...

  2. Java String.Format() 方法及参数说明

    转自:https://blueram.iteye.com/blog/441683 JDK1.5中,String类新增了一个很有用的静态方法String.format():format(Locale l ...

  3. GO开发:链表

    链表 type Student struct { Name string Next* Student } 每个节点包含下一个节点的地址,这样把所有的节点串起来了,通常把链表中的第一个节点叫做链表头 p ...

  4. java连接oracle并load sql从xml执行查询

    在ETL的时候,连接oracle并load sql执行是基础操作,需要注意的是记得执行结束后记得关闭connection, 现记录一下: 其中xml文件: <?xml version=" ...

  5. 阶段3 2.Spring_01.Spring框架简介_05.spring的优势

  6. 大众点评cat监控平台搭建

    参考官方文档:https://github.com/dianping/cat/wiki/readme_server 1.数据库相关 (1)创建数据库cat,并执行以下sql创建相关表: CREATE ...

  7. 十五:jinja2过滤器之实现自定义过滤器

    过滤器的本质就是函数,如果在模板中调用这个过滤器,那么就会将这个变量的值作为第一个参数传给过滤器函数,然后将函数的返回值作为滤器的返回值 1.在python文件中写好过滤的函数和逻辑2.将将函数注册到 ...

  8. flutter详解路由栈(二)

    前面,我们已经知道如何简单在路由栈中 push.pop 实例,然而,当遇到一些特殊的情况,这显然不能满足需求.学习 Android 的同学知道 Activity 的各种启动模式可以完成相应需求,Flu ...

  9. 如何利用Prometheus监控你的应用

    Prometheus作为一套完整的开源监控接近方案,因为其诸多强大的特性以及生态的开放性,俨然已经成为了监控领域的事实标准并在全球范围内得到了广泛的部署应用.那么应该如何利用Prometheus对我们 ...

  10. Django ModelChoiceField:过滤查询集并将默认值设置为对象

    我有一个Django Form类定义喜欢这个在Models: class AccountDetailsForm(forms.Form): ... adminuser = forms.ModelChoi ...