文章目录
- 1. 说明
- 2. Django自带中间件
- 3. 执行顺序
- 4. 自定义中间件
- 1. 流程
- 2. 模板
- 3. 示例
- 5. 中间件钩子函数
- 1. process_view
- 2. process_exception
- 3. process_template_response
- 4. 示例
1. 说明
- 中间件(middleware) 是一个镶嵌到Django的 request(请求)/response(响应) 处理机制中的一个钩子(hooks) 框架。它是一个可以修改Django全局输入或输出的一个底层插件系统
- Django 并不是接收到 request 对象后,马上交给视图函数或类 (view) 处理,也不是在 view 执行后立马把 response 返回给用户。一个请求在达到视图View处理前需要先经过一层一层的中间件处理,经过View处理后的响应也要经过一层一层的中间件处理才能返回给用户
HttpRequest -> Middleware -> View -> Middleware -> HttpResponse
- 应用场景
作用 | 示例 |
权限校验 | 禁止特定IP地址的用户或未登录的用户访问我们的View视图函数 |
限制用户请求 | 对同一IP地址单位时间内发送的请求数量做出限制 |
增添默认输入参数 | 在View视图函数执行前传递额外的变量或参数 |
打印日志 | 在View视图函数执行前或执行后把特定信息打印到log日志 |
改变输出内容 | 在View视图函数执行后对response数据进行修改后返回给用户 |
- 注意
装饰器也经常用于用户权限校验。但与装饰器不同,中间件对Django的输入或输出的改变是全局的。比如 @login_required 装饰器仅作用于单个视图函数
2. Django自带中间件
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',
]
中间件 | 作用 |
SecurityMiddleware | 为request/response提供了几种安全改进 |
SessionMiddleware | 开启session会话支持 |
CommonMiddleware | 基于 APPEND_SLASH 和 PREPEND_WWW 的设置来重写URL,如果APPEND_SLASH设为True,并且初始URL 没有以斜线结尾以及在URLconf 中没找到对应定义,这时形成一个斜线结尾的新URL |
CsrfViewMiddleware | 添加跨站点请求伪造的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值 |
AuthenticationMiddleware | 在视图函数执行前向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户,无它用不了 request.user |
MessageMiddleware | 开启基于Cookie和会话的消息支持 |
XFrameOptionsMiddleware | 对点击劫持的保护 |
GZipMiddleware | 压缩网站内容 |
LocaleMiddleware | 根据用户请求语言返回不同内容 |
ConditionalGetMiddleware | 给GET请求附加条件 |
3. 执行顺序
- 在 settings.py 注册中间件时一定要考虑中间件的执行顺序,中间件在 request 到达 view 之前是从上向下执行的,在 view 执行完后返回 response 过程中是从下向上执行的
4. 自定义中间件
1. 流程
- Django提供了两种编写自定义中间件的方式:函数和类
- 自定义中间件先在app所属目录下新建一个文件 middleware.py, 添加好编写的中间件代码,然后在项目settings.py中把它添加到MIDDLEWARE列表进行注册,添加时一定要注意顺序
2. 模板
# 1. 函数
def simple_middleware(get_response):
# 一次性设置和初始化
def middleware(request):
# 请求在到达视图前执行的代码
response = get_response(request)
# 响应在返回给客户端前执行的代码
return response
return middleware
# 2. 类
class SimpleMiddleware:
def __init__(self, get_response):
# 一次性设置和初始化
self.get_response = get_response
def __call__(self, request):
# 视图函数执行前的代码
response = self.get_response(request)
# 视图函数执行后的代码
return response
3. 示例
# 1. 函数,打印出执行每个请求所花费的时间
import time
def timeit_middleware(get_response):
def middleware(request):
start = time.time()
response = get_response(request)
end = time.time()
print("请求花费时间: {}秒".format(end - start))
return response
return middleware
# 2. 类,名为LoginRequiredMiddleware的中间件,实现全站要求登录
# 但是登录页面和开放白名单上的urls除外
from django.shortcuts import redirect
from django.conf import settings
class LoginRequiredMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.login_url = settings.LOGIN_URL
# 开放白名单,比如['/login/', '/admin/']
self.open_urls = [self.login_url] + getattr(settings, 'OPEN_URLS', [])
def __call__(self, request):
if not request.user.is_authenticated and request.path_info not in self.open_urls:
return redirect(self.login_url + '?next=' + request.get_full_path())
response = self.get_response(request)
return response
- request.path_info 用于获取当前请求的相对路径,如/articles/
- request.get_full_path() 用于获取当前请求完整的相对路径,包括请求参数,如/articles/?page=2
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',
'blog.middleware.timeit_middleware',
'blog.middleware.LoginRequiredMiddleware',
]
LOGIN_URL = "/admin/login/"
OPEN_URLS = ["/admin/"]
5. 中间件钩子函数
- process_view,process_exception,process_template_response 三个中间件钩子函数,分别在执行视图函数,处理异常和进行模板渲染时调用
1. process_view
process_view(request, view_func, view_args, view_kwargs):
- request 是HttpRequest对象
- view_func 是将使用的视图函数
- view_args 是将传递给视图的位置参数的列表
- view_kwargs 是将传递给视图的关键字参数的字典
Django会在调用视图函数之前调用process_view方法,返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果
2. process_exception
process_exception(self, request, exception)
- request:一个HttpRequest对象
- exception:一个exception是视图函数异常产生的Exception对象
这个方法只有在视图函数中出现异常了才执行,返回的值是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。该方法常用于发生异常时通知管理员或将其日志的形式记录下来。
3. process_template_response
process_template_response(self, request, response)
- request:一个HttpRequest对象
- response:一个response是TemplateResponse对象(由视图函数或者中间件产生)
该方法是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象)。该方法常用于向模板注入变量或则直接改变模板
4. 示例
- 函数
from django.http import HttpResponse
def timeit_middleware(get_response):
def middleware(request):
response = get_response(request)
return response
def process_view(request, view_func, view_args, view_kwargs)
return None or HttpResponse(xx)
def process_exception(self, request, exception):
return None or HttpResponse(xx)
def process_template_response(self, request, response)
return ...
middleware.process_view = process_view
middleware.process_exception = process_exception
middleware.process_template_response = process_template_response
return middleware
- 类
class MyClassMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_view(request, view_func, view_args, view_kwargs)
return None or HttpResponse(xx)
def process_exception(self, request, exception):
return None or HttpResponse(xx)
# 例子: 打印出异常
return HttpResponse(<h1>str(exception)</h1)
# 该方法仅对TemplateResponse输入有用,对render方法失效
def process_template_response(self, request, response)
response.context_data['title'] = 'New title'
return response