中间件
中间件介绍
官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在处理请求的特定的时间去执行这些方法。
打开Django项目的Settings.py文件,可以看到的MIDDLEWARE配置项。
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',
]
MIDDLEWARE配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。
自定义中间件
中间件可以定义五个方法:
- 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)
以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
每个方法有四个特征:
-
执行时间
-
执行顺序
-
参数
-
返回值
示例:
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self, request):
print("MD1里面的 process_request")
def process_response(self, request, response):
print("MD1里面的 process_response")
return response
# 记得在settings.py注册
process_request
def process_request(self, request):
执行时间: 视图函数之前
参数: request ==》 和视图函数中是同一个request对象
执行顺序: 按照注册的顺序 顺序执行
返回值:
-
None : 正常流程
-
HttpResponse: 后面的中间的process_request、视图函数都不执行,直接执行当前中间件中的process_response方法,倒叙执行之前的中间中process_response方法。
process_response
def process_response(self, request, response):
执行时间: 视图函数之后
参数:
-
request ==》 和视图函数中是同一个request对象
-
response ==》 返回给浏览器响应对象
执行顺序:按照注册的顺序 倒序执行
返回值:
HttpResponse:必须返回response对象
process_view
def process_view(self, request, view_func, view_args, view_kwargs):
执行时间:process_request之后,路由匹配完成,视图函数之前
参数:
-
request
==》 和视图函数中是同一个request对象 -
view_func
==》 视图函数 -
view_args
==》 视图函数的位置参数 -
view_kwargs
==》 视图函数的关键字参数
执行顺序:按照注册的顺序 顺序执行
返回值:
None : 正常流程
HttpResponse: 后面的中间的process_view、视图函数都不执行,直接执行最后一个中间件中的process_response方法,倒叙执行之前的中间中process_response方法。
process_exception
def process_exception(self, request, exception):
执行时间(触发条件):视图层面有错时才执行
参数:
-
request ==》 和视图函数中是同一个request对象
-
exception ==》 错误对象
执行顺序:按照注册的顺序 倒叙执行
返回值:
None : 交给下一个中间件取处理异常,都没有处理交由django处理异常,既常见的黄页。
HttpResponse: 后面的中间的process_exception不执行,直接执行最后一个中间件中的process_response方法,倒叙执行之前的中间中process_response方法。
process_template_response
def process_template_response(self,request,response):
执行时间(触发条件):视图返回的是一个templateResponse对象
参数:
request ==》 和视图函数中是同一个request对象
response ==》 templateResponse对象
执行顺序:按照注册的顺序 倒叙执行
返回值:
HttpResponse:必须返回response对象
登录态验证示例
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.login, name='login'),
url(r'^index/$', views.index, name='index'),
url(r'^home/$', views.home, name='home'),
]
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 == "admin" and pwd == "admin":
# 设置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")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>登录页面</title>
</head>
<body>
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<p>
<label for="user">用户名:</label>
<input type="text" name="user" id="user">
</p>
<p>
<label for="pwd">密 码:</label>
<input type="text" name="pwd" id="pwd">
</p>
<input type="submit" value="登录">
</form>
</body>
</html>
from django.utils.deprecation import MiddlewareMixin
class AuthMD(MiddlewareMixin):
white_list = ['/login/', ] # 白名单
black_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.black_list:
return HttpResponse('This is an illegal URL')
# 白名单的网址或者登陆用户不做限制
elif next_url in self.white_list or request.session.get("user"):
return
else:
return redirect("/login/?next={}".format(next_url))
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',
'middlewares.AuthMD'
]
AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。
如果URL在黑名单中,则返回This is an illegal URL的字符串;
访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;
正常的URL但是需要登录后访问,让浏览器跳转到登录页面。
注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。