Django边学边记——中间件
特点
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,用于全局修改Django的输入或输出。
每个中间件组件负责做一些特定的功能。中间件全部注册在setting.py中的 MIDDLEWARE 列表中。
中间件是可调用的,它接受请求并返回响应,就像视图一样。
中间件可以在6个位置介入:
服务器启动时
def __init__(self, get_response=None):
处理请求之前
def process_request(self, request):
处理视图之前
def process_view(self, request, view_func, view_args, view_kwargs):
处理模板响应前
def process_template_response(self, request, response):
响应返回前
def process_response(self, request, response):
抛出异常时
def process_exception(self, request,exception):
为了在于不同的阶段执行,对输入或输出进行干预,我们可以编写自己的中间件。
编写中间件一般用类实现,这个类可以随便写在那个py文件中,别忘记在setting.py中的 MIDDLEWARE 列表中导入就行。
中间件类我们可以模仿django中已经写好的中间件,在相应位置加上我们的代码就行。
也可以用继承的方法,继承自 django.utils.deprecation.MiddlewareMixin
第一种(创建个新的)
1.在项目中创建一个中间件包>创建中间件py文件
2.编写中间件程序代码
一般习惯于将中间件写成一个类 :
class SimpleMiddleware: def __init__(self, get_response): self.get_response = get_response # 服务器启动时 调用一次写在这里的代码 def __call__(self, request): # 处理请求之前 执行写在这里的代码,相当于 process_request(request) response = self.get_response(request) # 视图处理后,返回浏览器前 执行这里的代码 相当于 process_response(request,response) return response def process_view(self,request,view_func,*args,**kwargs): # 处理请求后,处理视图前,执行这里的代码 # 返回None或HttpResponse对象 pass
每个自定义的中间件类 必须有_init__ 和 __call__ 两个方法,写法也比较固定。一般按照文档说明中的格式套用即可,只需在相应位置加上自己的控制代码。
get_response参数是必需的,这个参数指的是下一个中间件或者view函数(如果是最后一个中间件)。
中间件也可以被写成这样的函数(习惯用类):
def simple_middleware(get_response): # One-time configuration and initialization. def middleware(request): # Code to be executed for each request before # the view (and later middleware) are called. response = get_response(request) # Code to be executed for each request/response after # the view is called. return response return middleware
3. 注册中间件模块
在项目setting.py 的MIDDLEWEAR列表 中注册自定义中间件模块
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', 'test.middleware.middleware.MyMd', ]
第二种(继承法)
需要哪个阶段介入,就从6个介入函数中选哪个
# 导入中间件的父类 from django.utils.deprecation import MiddlewareMixin class TestMiddleware1(MiddlewareMixin): """自定义中间件""" def process_request(self, request): """处理请求前自动调用""" print('process_request1 被调用') def process_view(self, request, view_func, view_args, view_kwargs): # 处理视图前自动调用 print('process_view1 被调用') def process_response(self, request, response): """在每个响应返回给客户端之前自动调用""" print('process_response1 被调用') return response
中间件顺序与分层
在请求阶段,在调用视图之前,Django 按照定义的顺序应用中间件 MIDDLEWARE
,自顶向下。
你可以把它想象成一个多道门的房子:每个中间件类都是一个“门”,视图在房子的最中间。如果请求通过所有门(每一个调用 get_response
)到达房子最中间的视图,那么响应将在返回的过程中也要通过进来的所有门出去(以相反的顺序)。
如果其中一道门决定不让进,并返回响应而不调用get_response,那么这道门后面的门都不会看到请求或响应。响应将只通过请求传入的相同层返回。
经典流程图如下:
其他中间件钩子
除前面讲到的,还有2种会用到的中间件方法:
1.异常处理:当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象
def process_exception(request,exception): pass
2.处理模板响应前:在每个请求上调用,返回实现了render方法的响应对象
def process_template_response(request, response): pass
实例应用
1.实现每个IP向 /pw 开头的地址 最多请求5次
class LimitIp: ip_dict = {} def __init__(self, get_response): self.get_response = get_response def __call__(self, request): tar_ip = request.META['REMOTE_ADDR'] if request.path_info.startswith('/pw'): count = self.ip_dict.get(tar_ip, 0) count += 1 self.ip_dict[tar_ip] = count if count > 5: return HttpResponse(f'你已经访问{count}次,超出访问限制') response = self.get_response(request) return response
2.实现让有权限的管理员可以在DEBUG关闭的情况下看到错误信息
import sys from django.views.debug import technical_500_response class ExceptionMiddleware(object): def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) return response def process_exception(self, request, exception): if request.user.is_admin: return technical_500_response(request, *sys.exc_info())