Django中间件探索
中间件方法及执行顺序
中间件五个方法:
1)process_request:不能有返回值,若在process_request有返回值,那么下面的中间件将不会执行,后面的URL以及视图函数也不会执行,直接执行当前的中间件的process_response方法。
2)process_response:默认情况下返回response, 即视图函数的返回值,如果在这个方法中自定义了返回值,将返回自定义返回值。
3)process_view:这个方法的调用时机在 Django 执行完 request 预处理函数并确定待执行的 view (即callback参数)之后,但在 view 函数实际执行之前。
4)process_exception:这个方法只有在 request 处理过程中出了问题并且view 函数抛出了一个未捕获的异常时才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。
5)process_template_response:默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户(注意不返回视图函数的return的结果了,而是返回视图函数 return值(对象)中rende方法的结果)
中间件执行顺序
1)在app创建middleware.py文件自定义中间件,在settings中注册
from django.utils.deprecation import MiddlewareMixin
class CustomizeMiddleware1(MiddlewareMixin):
def process_request(self, request):
print("中间件1请求")
def process_response(self, request, response):
print("中间件1返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("中间件1view")
class CustomizeMiddleware2(MiddlewareMixin):
def process_request(self, request):
print("中间件2请求")
def process_response(self, request, response):dd
print("中间件2返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("中间件2view")
如下图,由此可见中间件执行顺序,按照中间件的注册顺序依次往下,然后再反向。
自定义中间件验证登录
1)了解中间件之后可以编写中间件验证用户是否有权限或者登录,就没必要在每个视图函数去判断是否有权限。
# 登录
class LoginView(View):
def get(self, request):
form = LoginForm()
if request.user.is_authenticated:
return HttpResponseRedirect('/')
return render(request, 'login.html', {'form': form})
def post(self, request):
form = LoginForm(request.POST)
if form.is_valid():
data = form.cleaned_data
user = check(data['username'], data['password'])
request.session['user'] = data['username'] # 在这里存user
if user is not None:
if user is not False:
login(request, user)
return HttpResponseRedirect('/')
else:
return render(request, 'login.html', {'form': form, 'msg': '密码错误'})
else:
return render(request, 'login.html', {'form': form, 'msg': '账户不存在'})
return render(request, 'login.html', {'form': form})
# 中间件
class LoginMiddleware(MiddlewareMixin):
white_list = ['/login/', '/users/register/'] # 白名单
black_list = ['/tourial/contact/', ] # 黑名单 (测试)
def process_request(self, request):
print("中间件login验证请求")
next_url = request.path_info # 将要请求的url
# print(request.path_info, request.get_full_path())
user = request.session.get("user") # 获取session里的user
if next_url in self.white_list or user: # 判断url是否在白名单或者session里是否存在user
# print(user)
return None # 是的话直接返回None
elif next_url in self.black_list: # 如果存在于黑名单 直接返回HttpResponse
return HttpResponse('This is an illegal URL')
else:
return redirect("/login/?next={}".format(next_url)) # 都不是直接跳转到login界面
def process_response(self, request, response):
print("中间件login验证返回")
return response
LoginMiddleware中间件注册后,所有的请求都要走LoginMiddleware的process_request方法;
访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;
如果URL在黑名单中,则返回报错的字符串;
正常的URL但是需要登录后访问,让浏览器跳转到登录页面。
注:中间件中需要session,所以LoginMiddleware注册的位置要在session中间的下方。
也能在中间件中设置限制IP,前面也说了中间件的执行顺序是按照注册的顺序
# X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,
# 只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。
def get_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0] # 所以这里是真实的ip
else:
ip = request.META.get('REMOTE_ADDR') # 这里获得代理ip
return ip
class CustomizeMiddleware(MiddlewareMixin):
def process_request(self, request, response):
allowed_ip = ['192.168.1.1', '127.0.0.1']
# 允许/禁止访问的ip地址列表,判断请求ip, 放行/阻拦
if get_ip(request) not in allowed_ip:
return HttpResponse('您的IP地址无权访问')
else:
return None
那么 request.META 里面还有什么有用的数据呢?动手写一个简单的view函数来显示 request.META 的所有数据,这样你就知道里面有什么了。
def display_meta(request):
values = request.META.items()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return HttpResponse('<table>%s</table>' % '\n'.join(html))
附:Django请求流程图