文章目录
1. Django 中间件简介
官方解释称中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局
范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。但是由于其影响的是全局,所以需要谨慎使用
使用不当会影响性能。
简单来说中间件是在视图函数执行之前和执行之后做的一些额外操作,它本质上就是一个自定义类,类中定义了几个方法,
Django框架会在请求的特定的时间去执行这些方法,结构如下所示。
Django 自带中间件
在Django中自带7个中间件,如下示例
# 内置的安全机制,保护用户与网站的通信安全。
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 开启CSRF防护功能
'django.middleware.csrf.CsrfViewMiddleware',
# 开启内置的用户认证系统
'django.contrib.auth.middleware.AuthenticationMiddleware',
# 开启内置的信息提示功能
'django.contrib.messages.middleware.MessageMiddleware',
# 防止恶意程序点击劫持
'django.middleware.clickjacking.XFrameOptionsMiddleware',
查看自带中间件的源码可以发现它们是类,并且很多都带有 process_request 、process_response等方法,并且都继承了MiddlewareMixin类
2. Django 自定义中间件
Django给我们提供了创建自定义中间件的方式,通过创建自定义中间件来实现全局的功能,例如用户黑名单校验、用户访问频率校验、网站全局用户身份校验等等。
Django 提供了5个方法可以用来创建自定义中间件,如下示例
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
主要使用的是process_request和process_response方法
创建自定义中间件的流程
1.创建一个任意名称的文件夹例如 middleware
2.在该文件夹内创建一个任意名称的py文件例如
3.在该py文件内编写中间件类
4.在settings配置文件中注册
process_request
其作用是请求来的时候会从上往下依次执行配置文件中已注册的中间件里面的process_request方法,如果没有则直接跳过。
1. process_request有一个参数,就是request,这个request和视图函数中的request是一样的(在交给Django后面的
路由之前,对这个request对象可以进行一系列的操作)。
2. 由于request对象是一样的,所以我们可以对request对象进行一系列的操作,包括request.变量名=变量值,这样的操
作,我们可以在后续的视图函数中通过相同的方式即可获取到我们在中间件中设置的值。
3. 它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理
如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
使用示例
from django.utils.deprecation import MiddlewareMixin
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的内容')
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的内容')
然后执行一个视图函数,会发现process_request方法里的内容会自动打印,并且按照从上到下的顺序执行
'''注意点'''
在process_request方法中返回一个HttpResponse对象的话,用户请求不会继续往下执行,也就是被拦截了,并返回
process_request方法中的HttpResponse对象内容,也就是说,在第一个自定义中间件process_request方法中拦截后
不会执行下一个自定义中间件的process_request方法,如下示例
总结
中间件的process_request方法是在执行视图函数之前执行的。
当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
不同中间件之间传递的request都是同一个对象
process_response
响应走的时候会按照配置文件中注册的中间件从下往上的顺序依次执行每一个中间件里面的process_response方法,该方法必须要有两个形参,并且需要将形参response返回(response是视图函数的返回值),如果内部定义了返回了HttpResponse对象,会将返回给用户浏览器的内容替换成HttpResponse对象
使用示例
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, redirect
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第一个自定义中间件的process_response内容')
return responce
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return responce
'''注意点'''
1. process_response方法有俩个形参,为request、response。其中response是必须要返回的,因为其是视图函数的
返回值
2. 如下不返回response,而返回HttpResponse对象,那么原本视图函数的返回值就被替换了
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, redirect
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第一个自定义中间件的process_response内容')
return responce
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return HttpResponse('又被掉包了')
process_request、process_response 注意点:
如果process_request返回了HttpResponse对象,那么会从当前位置从下往上执行每一个process_response
如下图所示
process_view
process_view(self, request, view_func, view_args, view_kwargs)
该方法有四个参数
request HttpRequest对象。
view_func Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args 将传递给视图的位置参数的列表.
view_kwargs 将传递给视图的关键字参数的字典。view_args和view_kwargs都不包含参数(request)
Django会在路由匹配成功后调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的
process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,那么将不会执行Django的视图函数
而是直接在中间件中掉头,倒叙执行一个个process_response方法,最后返回给浏览器
使用示例
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, redirect
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第一个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第一个自定义中间件的process_view内容")
print(view_func, view_func.__name__)
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第二个自定义中间件的process_view内容")
print(view_func, view_func.__name__)
打印结果
这是第一个自定义中间件的process_request内容
这是第二个自定义中间件的process_request内容
这是第一个自定义中间件的process_view内容
<function Index at 0x000001481E7B6620> Index
这是第二个自定义中间件的process_view内容
<function Index at 0x000001481E7B6620> Index
这是第二个自定义中间件的process_response内容
这是第一个自定义中间件的process_response内容
'''注意点'''
如果process_view返回了HttpResponse对象,其流程大致如下图所示
process_template_response
process_template_response(self,request,response)
该方法有两个参数,一个HttpRequest对象,response是emplateResponse对象
该方法在视图函数执行完成后,且返回的对象中必须要有render属性对应的render方法时触发,顺序是倒序
使用示例
视图函数
class Index(View):
def get(self, request):
def render():
return HttpResponse('我是index里面的render函数')
obj = HttpResponse('index')
obj.render = render
return obj
# return render(request, 'index.html', locals())
def post(self, request):
return render(request, 'index.html', locals())
自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, redirect
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第一个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第一个自定义中间件的process_view内容")
def process_template_response(self, request, response):
print("这是第一个自定义中间件的process_template_response")
return response
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第二个自定义中间件的process_view内容")
def process_template_response(self, request, response):
print("这是第二个自定义中间件的process_template_response")
return response
打印结果
这是第一个自定义中间件的process_request内容
这是第二个自定义中间件的process_request内容
这是第一个自定义中间件的process_view内容
这是第二个自定义中间件的process_view内容
这是第二个自定义中间件的process_template_response
这是第一个自定义中间件的process_template_response
这是第二个自定义中间件的process_response内容
这是第一个自定义中间件的process_response内容
process_exception
process_exception(self, request, exception)
该方法有两个参数
一个是HttpRequest对象
一个exception是视图函数异常产生的Exception对象
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。
如果返回HttpResponse对象,Django将调用中间件中的process_response方法,并返回给浏览器
如果返回None,则交给下一个中间件的process_exception方法来处理异常。执行顺序按照中间件注册顺序的倒序执行。
使用示例
视图函数
class Index(View):
def get(self, request):
def render():
return HttpResponse('我是index里面的render函数')
obj = HttpResponse('index')
obj.render = render
# 抛出异常
raise ValueError("hh")
return obj
自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, redirect
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('这是第一个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第一个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第一个自定义中间件的process_view内容")
def process_template_response(self, request, response):
print("这是第一个自定义中间件的process_template_response")
return response
def process_exception(self, request, exception):
print('exception', exception)
print('这是第一个中间件里面的process_exception')
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第二个自定义中间件的process_view内容")
def process_template_response(self, request, response):
print("这是第二个自定义中间件的process_template_response")
return response
def process_exception(self, request, exception):
print('exception', exception)
print('这是第二个中间件里面的process_exception')
打印结果
这是第一个自定义中间件的process_request内容
这是第二个自定义中间件的process_request内容
这是第一个自定义中间件的process_view内容
这是第二个自定义中间件的process_view内容
exception hh
这是第二个中间件里面的process_exception
exception hh
这是第一个中间件里面的process_exception
这是第二个自定义中间件的process_response内容
这是第一个自定义中间件的process_response内容
给 MyMdd2 添加返回值
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('这是第二个自定义中间件的process_request内容')
def process_response(self, request, responce):
print('这是第二个自定义中间件的process_response内容')
return responce
def process_view(self, request, view_func, view_args, view_kwargs):
print("这是第二个自定义中间件的process_view内容")
def process_template_response(self, request, response):
print("这是第二个自定义中间件的process_template_response")
return response
def process_exception(self, request, exception):
print('exception', exception)
print('这是第二个中间件里面的process_exception')
return HttpResponse(str(exception))
打印结果
这是第一个自定义中间件的process_request内容
这是第二个自定义中间件的process_request内容
这是第一个自定义中间件的process_view内容
这是第二个自定义中间件的process_view内容
exception hh
这是第二个中间件里面的process_exception
这是第二个自定义中间件的process_response内容
这是第一个自定义中间件的process_response内容
在第二个中间件中process_exception添加HttpResponse返回值后,不会执行第一个中间件的process_exception方法。
流程图