一个完整的中间件设有5个钩子函数,Django将用户请求到网站的过程进行阶段划分,每个阶段对应执行某个钩子函数:
- __ init __ ():初始化函数,运行Django将自动执行该函数
- process_request():完成请求对象的创建,但用户访问的网址尚未与网站的路由地址匹配
- process_view():完成用户访问的网址与路由地址的匹配,但尚未执行视图函数
- process_exception():在执行视图函数的期间发生异常
- process_response():完成视图函数的执行,但尚未将响应的内容返回浏览器
每个钩子函数都有固定的执行顺序,以MyDjango为例,在MyDjango文件夹中创建myMiddleware.py文件,该文件用于定义中间件。
在定义中间件之前,首要实现网站功能,分别在MyDjango的urls.py、index的urls.py、index的views.py和templates的index.html中编写以下代码:
# MyDjango的urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(('index.urls', 'index'), namespace='index'))
]
# index的urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('', index, name='index'),
]
# index的views.py
from django.shortcuts import render
from django.http import Http404
def index(request):
if request.GET.get('id', ''):
raise Http404
return render(request, 'index.html', locals())
<!--templates的index.html-->
<!DOCTYPE html>
<html lang="zh-hans">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<div>Hello Django</div>
</body>
</html>
视图函数index设置了主动抛出404异常,用于验证钩子函数process_exception。
下一步在MyDjango的myMiddleware.py中定义中间件MyMiddleware:
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
print('this is __init__')
def process_request(self, request):
"""生成请求对象后,路由匹配之前"""
print('this is process_request')
def process_view(self, request, func, args, kwargs):
"""路由匹配后,视图函数调用之前"""
print("this is process_view")
def process_exception(self,request,exception):
"""视图函数发生异常时"""
print('this is process_exception')
def process_response(self, request, response):
"""视图函数执行后,响应内容返回浏览器之前"""
print('this is process_response')
return response
运行MyDjango,项目将自动运行中间件MyMiddleware的初始化函数 __ init __ (),初始化函数必须设置函数参数get_response,还需要将参数get_response设为类属性self.get_response,否则在访问网站时将提示AttributeError异常。
当用户在浏览器上访问某个网址时,Django为当前用户创建请求对象,请求对象创建成功后,程序执行钩子函数process_request,通过重写该函数可以获取并判断用户的请求是否合法。函数参数request代表用户的请求对象,他与视图函数的参数request相同。
钩子函数process_request执行完成后,Django将用户访问的网址与路由信息进行匹配,在调用函数或视图类之前,程序将执行钩子函数process_view。函数参数request代表用户的请求对象;参数func代表视图函数或视图类的名称;参数args和kwargs是路由信息传递给视图函数或视图类的变量对象。
钩子函数process_view执行完毕后,Django将执行视图函数或视图类。如果在执行视图函数或视图类的过程中出现异常报错,程序就会执行钩子函数process_exception。函数参数request代表用户的请求对象,参数exception代表异常信息。
视图函数或视图类执行完成后,Django将执行钩子函数process_response,该函数可以对视图函数或视图类的响应内容进行处理。当钩子函数prrocess_response执行完成后,程序才把响应内容返回给浏览器生成网页信息。
最后我们在MyDjango的settings.py中添加自定义中间件MyMiddleware:
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',
'MyDjango.myMiddleware.MyMiddleware'
]
在Pycharm中运行MyDjango,在浏览器上访问127.0.0.1:8000/?id=1,由于路由地址没有请求参数id,因此视图函数将主动抛出404异常,Django将触发process_exception函数。