10.django中间件
一、中间件简介
中间件就是介于request和response处理之间的一道处理过程,相对比较轻量级,在全局上改变django的输入与输出,因为改变的是全局,所以要谨慎使用。
中间件其实就是在我们视图函数执行前执行的一些额外的操作,本质上就是自定义一个类,定义了一些方法,我们的django项目一直都是使用中间件的,打开setting.py文件
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',
# 自定义中间件
'app01.utils.mymiddleware.DM1',
'app01.utils.mymiddleware.SeesiongAuth',
]
最后两条是我们自定义的中间件,MIDDLEWARE配置项是一个列表,列表元素是一个个字符串,也是一个个中间件。
中间件中可以写五个方法,
二、自定义中间件
1、中间件中可以定义的方法
中间件的可以定义5个方法(主要是process_request和process_response):
- process_request(self, request)
- process_response(self, request, reponse)
- process_view(self, request, view_func, view_args, view_kwargs)
- process_template_response(self, request, response)
- process_exception(self, request, exception)
以上方法的返回值是一个None或者一个HttpResponse对象,则直接将该对象返回给用户。
2、自定义中间件
在项目中创建一个包,一般以utils作为包名,表示一个公用的组件,创建一个py文件。
from django.utils.deprcation import MiddlewareMixin
# 自定义的中间不是一定要有这两个方法
class DM1(MiddlewareMixin):
def process_request(self, request):
print("MD1请求")
return None
def process_response(self, request, response):
print('MD1响应')
return response
3、中间件中的方法
1)process_request
process_request有一个参数,就是request,这和视图函数中request是一样的,多个中间件的request对象也是一样的,它的返回值可以是None也可以是HttpResponse对象。返回值是None,按照正常流程走下去,交给下一个中间件处理,如果是HttpResponse对象,django将不执行视图函数,将相应对象返回给浏览器。
2)process_response
他有两个参数,一个是request,一个是response,request是上述例子中的对象,response是视图函数返回的HttpResponse对象,该方法的返回值也必须是HttpResponse对象。
process_response方法实在视图函数之后执行的,多个中间件的process_response方法是按照MIDDLEWARE中注册顺序倒序执行的,也就是说第一个中间件的request方法先执行,response方法最后执行。
# 中间件个方法的执行顺序
MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图
MD1里面的 process_response
MD2里面的 process_response
3)process_view
process_view(self, request, view_func, view_args, view_kwargs)
参数:
- request是HttRequest对象,
- 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方法并将应用到该HttpResponse并返回结果。
4)process_exception
process_exception(self, request, exception)
参数:
- 一个HttpRequest对象
- 一个exception是视图函数异常产生的Exception对象
这个方法只有在视图函数执行异常才执行,返回值可以是一个None也可以是一个httpResponse对象。如果是HttpResponse对象,django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。执行顺序也是按照中间件的注册顺序的倒叙执行。
5)process_template_response
process_template_response(self, request, response)
参数:
- 一个HttpRequest对象,
- response是TemplateResponse对象(由视图函数或中间件产生)
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
3、中间件的执行顺序
中间的执行顺序是按照MIDDLEWARE列表中定义的顺序来执行的(红色箭头标识的),即请求最后一个经过的中间件是该请求对应响应的第一个中间件。
请求对应的是process_request()方法,响应对应的是process_response()方法。
三、中间件白名单
# 自定义中间件.py
from django.urls import reverse
class SeesiongAuth(MiddlewareMixin):
def process_request(self, request):
# 设置白名单, reverse别名反向解析
white_list = [reverse('login'), '/home/']
if request.path in white_list:
return None
is_login = request.session.get('is_login')
if is_login is True:
return None
else:
return redirect('login')
如果不设置白名单,这种写法导致浏览器向服务器发送请求,服务器判断sessionid发现其为空,重定向到login页面导致其重新判断sessionid的值,重定向多次,所以要设置白名单
四、中间件版登陆验证
# urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/$', views.index),
url(r'^login/$', views.login, name='login'),
]
# views.py
from django.shortcuts import render, HttpResponse, redirect
def index(request):
return HttpResponse('this is index')
def home(request):
return HttpResponse('this is home')
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "Q1mi" and pwd == "123456":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
# login.html
from django.shortcuts import render, HttpResponse, redirect
def index(request):
return HttpResponse('this is index')
def home(request):
return HttpResponse('this is home')
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "Q1mi" and pwd == "123456":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
# middlewares.py
class AuthMD(MiddlewareMixin):
white_list = ['/login/', ] # 白名单
balck_list = ['/black/', ] # 黑名单
def process_request(self, request):
from django.shortcuts import redirect, HttpResponse
next_url = request.path_info
print(request.path_info, request.get_full_path())
if next_url in self.white_list or request.session.get("user"):
return
elif next_url in self.balck_list:
return HttpResponse('This is an illegal URL')
else:
return redirect("/login/?next={}".format(next_url))
# setting.py注册
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',
'middlewares.AuthMD',
]
五、中间件案例
应用案例:
1、做IP访问频率限制(可以防止爬虫)
2、URL过滤(白名单)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗