中间件
2. 自定义中间件
上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin
需要导入
from django.utils.deprecation import MiddlewareMixin
一、process_request,process_response
process_response方法必须返回response!
url等略,下面只展示关键代码
views.py:
from django.shortcuts import render,HttpResponse,redirect
def index(request):
print("view函数...")
return HttpResponse("OK")
应用/my_middlewares.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
def process_response(self,request,response):
print("Md2返回")
return response
执行结果
Md1请求
Md2请求
view函数...
Md2返回
Md1返回
注意:如果当请求到达请求1的时候直接不符合条件返回,即return HttpResponse("Md1中断"),程序(跳过process_view,url,视图函数,process_exception)将把请求直接发给中间件1返回,,然后依次返回到请求者,结果如下:
Md1请求
Md1返回
流程图如下:
二、process_view
process_view使用如下
process_view(self, request, callback, callback_args, callback_kwargs)
callback 是当前请求的视图函数,callback_args, callback_kwargs是请求的参数,这一步在视图层之前执行
my_middlewares.py修改如下
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md1view")
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
return HttpResponse("Md2中断")
def process_response(self,request,response):
print("Md2返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md2view")
结果如下:
Md1请求
Md2请求
Md1view
Md2view
view函数...
Md2返回
Md1返回
流程如下:
process_view可以用来调用视图函数:
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
# Md1 view 中断
# return HttpResponse("hello")
response=callback(request,*callback_args,**callback_kwargs)
return response
执行结果:
Md1请求
Md2请求
view函数...
Md2返回
Md1返回
注意:process_view如果有返回值HttpResponse类的相应函数,会越过其他的process_view以及视图函数,直接依次执行所有的process_response。
三、process_exception
process_exception是当视图函数抛出错误后执行的(视图函数没有解决错误)!
使用方法:
process_exception(self, request, exception)
自定义示例修改如下:
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
# return HttpResponse("hello")
# response=callback(request,*callback_args,**callback_kwargs)
# return response
print("md1 process_view...")
def process_exception(self):
print("md1 process_exception...")
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
# return HttpResponse("Md2中断")
def process_response(self,request,response):
print("Md2返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("md2 process_view...")
def process_exception(self):
print("md1 process_exception...")
结果:
Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
Md2返回
Md1返回
当views出现错误时:
将md2的process_exception修改如下:
def process_exception(self,request,exception):
print("md2 process_exception...")
return HttpResponse("error")
结果如下
Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
md2 process_exception...
Md2返回
Md1返回
注意:同process_view,如果process_exception有返回值HttpResponse类的相应函数,会越过其他的process_exception,直接依次执行所有的process_response。
3. 案例展示
- 通过中间件实现用户认证--session查询
- 限制每10秒访问不超过4次!
项目文件/setting.py
MIDDLEWARE = [
...其定义的中间件
'app01.my_middlewares.AuthMiddleware',
]
# 配置不需要登录验证的白名单
WHITE_LIST = ['/login/', '/reg/', '/logout/']
项目文件/urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('index/', views.index),
]
应用文件夹/models.py
from django.db import models
class IpInfo(models.Model):
id = models.AutoField(primary_key=True)
addr = models.CharField(max_length=15)
timestamp = models.FloatField()
accessTime = models.IntegerField(default=0)
应用文件夹/自定义中间件my_middlewares.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,redirect,render
# 从配置文件引入不需要认证的自定义白名单
from AjaxDemo.settings import WHITE_LIST
from django.db.models import F
from app01.models import IpInfo
import time
class AuthMiddleware(MiddlewareMixin):
def process_request(self, request):
"""获取客户端的IP
有些网站服务器会使用ngix等代理http,或者是该网站做了负载均衡,
导致使用remote_addr抓取到的是1270.0.1,这时使用HTTP_X_FORWARDED_FOR
才获得是用户的真实IP。推荐使用以下代码:
"""
if request.META.get('HTTP_X_FORWARDED_FOR', None):
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR']
# 限制用户10秒内只能
now = time.mktime(time.gmtime())
clientQ = IpInfo.objects.filter(addr=ip)
client = clientQ.first()
if not client:
IpInfo.objects.create(addr=ip, timestamp=now, accessTime=1)
else:
last_access_time = client.timestamp
accessTimes = client.accessTime
print("持续时间:", now - last_access_time)
if now - last_access_time < 10:
if accessTimes > 3:
return HttpResponse("本次访问被限制,请耐心等待!或者,你是一个机器人儿也说不定!")
else:
clientQ.update(accessTime=F('accessTime') + 1)
else:
clientQ.update(addr=ip, timestamp=now, accessTime=1)
if request.path in WHITE_LIST:
return None # 不执行操作
# 重定向到登录页面
if not request.user.is_authenticated:
return redirect('/login/')
应用文件夹/views.py
def index(reqest):
print("in views.........")
return HttpResponse("in views")