Django 处理http请求之中间件
Django处理http请求之中间件
by:授客 QQ:1033553122 欢迎加入全国软件测试交流QQ群:7156436
测试环境
Win7
Django 1.11
自定义中间件
中间件“工厂”是一个携带一个可调用get_response参数并返回一个中间件的的可调用对象。中间件则是一个携带request参数并返回一个response的可调用对象,正如view视图函数。
中间件可以写成类似如下的函数(假设以下代码位于 my_middleware.py文件中,项目结构如下):
def simple_middleware(get_response):
print('进入中间件')
def middleware(request):
# 针对每个request,这里的代码,会在view、后续中间件被调用之前执行(Code to be executed for each request before the view (and later middleware) are called.)
response = get_response(request)
# 针对每个request,这里的代码,会在view、后续中间件被调用之后执行(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):
# 针对每个request,这里的代码,会在view、后续中间件被调用之前执行(Code to be executed for each request before the view (and later middleware) are called.)
response = self.get_response(request)
# 针对每个request,这里的代码,会在view、后续中间件被调用之前执行(Code to be executed for each request before the view (and later middleware) are called.)
return response
django提供的get_response可能是实际view视图(如果当前中间是list中配置的最后一个中间件)、下一个中间件,当前中间件不需要知道它是啥。
中间件可以放在python path中的任何地方
__init__(get_response)
中间件工厂必须接受一个get_response参数,可以为中间件初始化一些全局状态,但是要注意:
- Django只允许用get_response初始化中间件,所以__init__()定义不能包含其它任何参数的。
- 和__call__()方法不一样,针对每个request,__call__()都会被调用一次,而__init__()仅在web 服务器启动时被调用一次(注意:实践表明 setting.py中 DEBUG = True时,启动服务时,__init__()可能被调用两次)
标记不被使用的中间件
在对应中间件的 __init__() 方法中抛出 MiddlewareNotUsed,Django将会在处理中间件时移除对应的中间件,并在DEBUG设置为True的情况下,往django.request logger中写入一条调试消息。
激活中间件
添加目标中间件到settings.py中的MIDDLEWARE list中以激活中间件,注意新增中间件后需要重启服务器。
MIDDLEWARE中,每个中间件以一个字符串表示:指向中间件工厂类、函数的全python路径。如下:
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',
'website.middleware.my_middleware.simple_middleware',
'website.middleware.my_middleware.SimpleMiddleware',
]
MIDDLEWARE可以配置为空,但是强烈建议至少包含CommonMiddleware
中间件在MIDDLEWARE中的顺序很关键,因为一个中间件可能会依赖另一个中间件。例如 AuthenticationMiddleware在会话中存储已授权用户信息,所以,它必须在SessionMiddleware之后运行,所以,自定义中间件建议都放到最后面。See Middleware ordering for some common hints about ordering of Django middleware classes。
中间件顺序和分层
request阶段,view调用之前,Django会按顺序-中间件在MIDDLEWARE中的定义,从上往下(索引从小到大),把中间件作用于request(During the request phase, before calling the view, Django applies middleware in the order it’s defined in MIDDLEWARE, top-down)
可以把它看成一个洋葱:每个中间件类都是一层包裹了view视图(洋葱的核心)的皮,如果请求通过了洋葱所有皮(每层都会调用get_response以便把request传递给下一层),到达核心view,那么将按相反的顺序,把response一层一层的往外传。
如果其中一层短路了,没有调用get_response的情况下,返回了response,该层所包裹的所有层(包括view视图)将看不到当前request和response。response只会经过request已经通过的层。
其它中间件钩子
除了上述描述的基础的request/response中间件模式,还可以添加以下三种特定的方法给基于类的中间件:
process_view()
process_view
(request, view_func, view_args, view_kwargs)
request 为一个 HttpRequest 对象。
view_func为Django即将调用的python函数 (实际函数对象,而非表示函数名称的字符串)
view_args 传递给view函数的位置参数list列表
view_kwargs 传递给view函数的字典参数,不管是view_args 还是 view_kwargs都不包含第一个参数(request).
process_view() 在Django调用view之前,__call__()被调用之后被调用,如下:
__call__() ->process_view() -> view function -> __call__()
函数应该返回None或者一个HttpResponse对象。如果返回None,Django将继续处理request,执行其它中间件的process_view(),最后执行对应的view。如果返回一个HttpResponse对象,Django将不会调用对应的view及后续的process_exception(), process_template_response()等,直接调用对应的response中间件作用于该response对象并返回结果.
注意:
应该避免在view视图运行之前,在中间件内部访问 request.POST,因为这将阻止该中间件之后的任何视图 modify the upload handlers for the request(Accessing request.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, and should normally be avoided)
CsrfViewMiddleware类可以被看做一个异常,因为它提供csrf_exempt() 和csrf_protect()装饰器,可以显示控制在哪里进行CSRF校验。 (The CsrfViewMiddleware class can be considered an exception, as it provides the csrf_exempt() andcsrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should occur
process_exception()
process_exception
(request, exception)
request 为一个 HttpRequest 对象。
exception 为view视图函数的一个 Exception 对象。
当view抛出一个异常时,Django才会调用process_exception()。函数应该返回None或者一个HttpResponse对象。如果返回一个HttpResponse对象,将应用template response和response中间件并返回上述描述的HttpResponse对象,结果给浏览器,否则走默认的异常处理(default exception handling )
相反的,response阶段(包括process_exception),按逆序运行中间件。如果异常中间件返回了一个response,位于该中间件前面的中间件(MIDDLEWARElist 中对应索引比当前中间件的索引小的中间件)的process_exception都不会被调用。
process_template_response()
process_template_response
(request, response)
request 为一个 HttpRequest 对象。
response 为Django view、中间件返回的一个TemplateResponse对象
process_template_response() 在view视图执行完成后才被调用。如果response实例有render()方法,它将被视为TemplateResponse 。形如:
from django.template.response import TemplateResponse
def test_page(request):
return TemplateResponse(request, 'website/pages/mytest.html',{})
它必须返回实现了render方法的response对象。可以通过改变response.template_name和response.context_data更改给定response,或者返回一个全新的TemplateResponse
无需显示的渲染response--response将在所有template response中间件调用完成后自动被渲染。
response阶段(包括process_template_response()),按逆序运行中间件。
Dealing with streaming responses
不同于HttpResponse,StreamingHttpResponse沒有content属性,因此中间件不能认为所有的响应都有content 属性,如果想要访问content,需要测试流式响应:
if response.streaming:
response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
response.content = alter_content(response.content)
注意:streaming_content被假定为太大而不能存放在内存中,响应中间件可以将它包裹在一个生成器中,但是不能消费它,通常如下所示:
Def wrap_streaming_content(content):
for chunk in content:
yield alter_content(chunk)
Exception handling
略
例子1
# -*- coding: utf-8 -*-
__author__ = 'shouke'
# from django.http import HttpResponse
class SimpleMiddleware1:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
print('call __init__ in SimpleMiddleware1')
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
print('call __call_ in SimpleMiddleware1 before the view is called')
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
print('call __call_ in SimpleMiddleware1 after the view is called')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('call process_view in SimpleMiddleware1')
# return HttpResponse('shouke')
def process_template_response(self, request, response):
print('call process_template_response in SimpleMiddleware1')
return response
def process_exception(self, request, exception):
print('call process_exception in SimpleMiddleware1')
class SimpleMiddleware2:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
print('call __init__ in SimpleMiddleware2')
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
print('call __call_ in SimpleMiddleware2 before the view is called')
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
print('call __call_ in SimpleMiddleware2 after the view is called')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('call process_view in SimpleMiddleware2')
def process_template_response(self, request, response):
print('call process_template_response in SimpleMiddleware2')
return response
def process_exception(self, request, exception):
print('call process_exception in SimpleMiddleware2')
# return HttpResponse('shouke')
View函数
def test_page(request):
print('call view function test_page')
# 1/0
return TemplateResponse(request, 'website/pages/mytest.html',{})
中间件配置
MIDDLEWARE = [
……
'website.middleware.my_middleware.SimpleMiddleware1',
'website.middleware.my_middleware.SimpleMiddleware2',]
运行结果
Upgrading pre-Django 1.10-style middleware
From django.utils.deprecation import MiddlewareMixin
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
Django提供了django.utils.deprecation.MiddlewareMixin来简化中间件类的创建,MiddlewareMixin兼容 MIDDLEWARE 和老版本的 MIDDLEWARE_CLASSES。Django包含的所有中间件类都是兼容彼此的配置的。
如果使用 MIDDLEWARE_CLASSES, 将不会调用__call__;直接调用 process_request() 和process_response()
大多数情况下,直接从MiddlewareMixin继承创建中间件就够了。
使用 MIDDLEWARE 和MIDDLEWARE_CLASSES的区别?
略
例子2
修改中间件代码如下,其它保持不变
# -*- coding: utf-8 -*-
__author__ = 'shouke'
from django.utils.deprecation import MiddlewareMixin
# from django.http import HttpResponse
class SimpleMiddleware1(MiddlewareMixin):
def process_request(self, request):
print('call process_request in SimpleMiddleware1')
def process_response(self, request, response):
print('call process_response in SimpleMiddleware1')
return response
class SimpleMiddleware2(MiddlewareMixin):
def process_request(self, request):
print('call process_request in SimpleMiddleware2')
def process_response(self, request, response):
print('call process_response in SimpleMiddleware2')
return response
运行结果
说明:
process_request在调用view函数视图之前执行;
Process_response在调用view函数视图之后执行;
参考链接
https://docs.djangoproject.com/en/2.1/topics/http/middleware/
https://docs.djangoproject.com/en/2.1/_modules/django/middleware/common/#CommonMiddleware
Django 处理http请求之中间件的更多相关文章
- Django框架10 /sweetalert插件、django事务和锁、中间件、django请求生命周期
Django框架10 /sweetalert插件.django事务和锁.中间件.django请求生命周期 目录 Django框架10 /sweetalert插件.django事务和锁.中间件.djan ...
- django系列8.2--django的中间件流程
Django请求流程图 请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpRe ...
- django系列8.1--django的中间件01 自定义中间件的5个方法
一.Django中的中间件 Django中间件定义: Middleware is a framework of hooks into Django's request/response process ...
- Django 补充models操作,中间件, 缓存,信号,分页
1.Model 一对多 补充 models如下: class UserType(models.Model): caption = models.CharField(max_length=16) cla ...
- Django --- cookie与session,中间件
目录 1.cookie与session 1.cookie 2.session 2.中间件 1.中间件作用 2.用户可以自定义的五个方法 3.自定义中间件 1.cookie与session 1.cook ...
- 玩转Django的POST请求 CSRF
玩转Django的POST请求 CSRF 不少麻油们玩django都会碰到这个问题,POST请求莫名其妙的返回 403 foribidden,希望这篇博文能解答所有问题 三种方法 To enable ...
- Django跨域请求之JSONP和CORS
现在来新建一个Django项目server01,url配置为 url(r'^getData.html$',views.get_data) 其对应的视图函数为get_data: from django. ...
- Django添加防跨站请求伪造中间件
第一步: 在全局设置中打开此中间件: MIDDLEWARE_CLASSES = [ ... 'django.middleware.csrf.CsrfViewMiddleware', ... ] ...
- Django框架(十七)—— 中间件、CSRF跨站请求伪造
目录 中间件 一.什么是中间件 二.中间件的作用 三.中间件执行顺序 四.自定义中间件 1.导包 2.定义类,继承MiddlewareMixin 3.在视图函数中定义一个函数 4.在settings的 ...
- django 启动和请求
Django运行方式 调试模式 直接 python manage.py runserver python manage.py runserver python manage.py runserver ...
随机推荐
- PHP 网络通信底层原理分析
一.引言 我们日常的程序开发大多数都是以业务为主,很少会接触到底层逻辑.对于我们程序员来说,了解程序的底层运行逻辑,更有助于提升我们对程序的理解.我相信大多数的人,每天基本上都是完成业务需求.当然,完 ...
- Android 12(S) MultiMedia Learning(九)MediaCodec
这一节来学习MediaCodec的工作原理,相关代码路径: http://aospxref.com/android-12.0.0_r3/xref/frameworks/av/media/libstag ...
- Android 12(S) MultiMedia Learning(八)NuPlayer Renderer
NuPlayer的AVSync由Renderer实现,接下来主要来看AVSync的工作原理 相关代码位置: NuPlayerRenderer.cpp - OpenGrok cross referenc ...
- ceph deploy部署ceph集群 ceph扩容 rbd存储
架构拓扑 节点主机 节点IP 节点角色 OS ceph-admin 10.0.0.60 admin deploy mds centos7 ceph-node1 10.0.0.61 mon osd md ...
- bash: _get_comp_words_by_ref: command not found 报错
没有安装补全的包 错误信息 bash: _get_comp_words_by_ref: command not found 表明你的 shell 中可能存在补全功能的问题. 通常,这种错误发生在你的系 ...
- webpack js兼容处理
webpack在不需要引入任何loader可以对于js进行打包处理,但是它不会对于js兼容性进行任务的处理,而我们编写的项目是需要在不同的浏览器中运行的,此时就需要对于js的兼容性在打包过程中进行对应 ...
- C#.NET AES CBC 加密
重点: 1. KEY 和 IV 转 byte[] 时的编码. 2.要加密的字符串转 byte[] 时的编码. 3.AES 的PADDING,MODE. 4.加密后的byte[] 转字符串时的编码. 先 ...
- 记一次 .NET某游戏币自助机后端 内存暴涨分析
一:背景 1. 讲故事 前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机类型的 ...
- vue饼图
结果图 原型 1 <template> 2 <!-- 左右柱状图 --> 3 <div ref="rankEcharts" :style=" ...
- 项目管理--PMBOK 读书笔记(3)【项目经理的角色 】
思维导图软件工具:https://www.xmind.cn/ 源文件地址:https://files-cdn.cnblogs.com/files/zj19940610/项目经理的角色.zip