django8-django的中间件

1.django的客户请求流程

  之前登录功能 ,需要获取用户的sesssion ,但是每个视图函数都要加装饰器来校验很不合理 ,中间件就可以解决这个问题 

  用户客户端--->wsgi(封装了request对象)--->中间件(框架hook)--->路由--->views--->models--->db--->template---中间件--->wsgi--->客户端

 

2.什么是中间件

  django中间件用来处理django的请求和响应框架级别的钩子 ,在全局范围内改变django的输入和输出 ,有多种类型中间件, 每个中间件都可以完成特定功能 ,可以帮助我们在执行视图函数前后完成额外操作 ,本质是类

  settings中MIDDLEWARE配置的就是中间件信息 ,字符串也是一个个类 ,也就是一个个中间件 ,可以通过import点击查看类

 

3.自定义中间件

  5种中间件 ,关注点在于 参数! 执行的时机! 执行顺序! 返回值! 

  本质就是类 ,类中定义下前面的五种方法 ,在不同时机执行产生不同作用!

  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)

  

  1)process_request(self,request)

    参数: wsgi返回的request对象

    执行时间: 在收到request后执行之前 (截断不满足要求的请求)

    执行顺序: 按照setting注册顺序执行 ,在注册的类中按顺序拿出每个类中这个方法执行

    返回值: 

      当返回值为空None: url-->views

      当返回response对象: 直接返回客户端 

##middle/middles.py 一个类就是一个中间件 ,可以写多个
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MD1 process_request')
        # return HttpResponse('拒绝访问')    #如果return那么就会直接返回客户端

##settings.py注册
MIDDLEWARE = [
...
    'middle.middles.MD1',
...
]

  2)process_response(self,request,response)

    参数: wsgi返回的request对象 ,response对象(可能是视图函数返回的 ,也可能是process_request返回的)

    执行时机: 在视图函数执行之后 ,还可能是是process_request有返回值之后按顺序执行

    执行顺序: 按照setting注册顺序倒序执行 ,在注册的类中倒叙获取每个类中的process_response方法执行

    返回值: 必须返回response对象

##/middle/middles.py  写两个中间件查看执行顺序
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MD1 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD1 process_response')
        # return HttpResponse('拒绝访问')
        return response

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD2 process_response')
        # return HttpResponse('拒绝访问')
        return response

##settings 注册两个中间件类
MIDDLEWARE = [
...
    'middle.middles.MD1',
    'middle.middles.MD2',
...
]

  3)process_view(self,request,view_func ,view_args, view_kwargs)

    参数: wsgi给的request对象 ,view_func匹配本次执行视图函数 ,view_args匹配本次视图函数位置参数 ,view_kwargs匹配本次视图函数关键字参数

    执行时机: 在url匹配到视图函数后执行 ,再执行视图函数

    执行顺序: 按照setting注册顺序执行

    返回值: 

      返回值为空: 正常流程(process_request--->url--->process_view--->views.py--->process_response)

      response对象: 截断流程(process_request--->url--->process_view(直接跳过所有view方法,和所有视图函数直接返回response)-->process_response)

##middle/middles.py 有返回值的view ,观察执行结果
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MD1 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD1 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD1 process_view', view_func)
        return HttpResponse('test')

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD2 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD2 process_view', view_func)


###执行结果
MD1 process_request
MD2 process_request
MD1 process_view <function presslist at 0x0408BF60>        #MD1有return ,MD2的view就不执行了直接跳到response
MD2 process_response
MD1 process_response

  4)process_exception(self ,request, exception)

    参数: wsgi返回的request对象 ,exception视图函数的异常

    执行时机: 在执行视图函数 ,有异常的情况

    执行顺序: 按setting的注册倒序执行 

    返回值: 

      返回值为空: 交给下一个process_exception处理

      返回response对象: 跳过其他process_exception ,开始process_response的倒叙顺序执行  (如果所有的exception都没处理这个异常 ,那么最后会由django做异常处理)

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse


class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MD1 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD1 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD1 process_view', view_func)

    def process_exception(self, request, exception):
        print('MD1 process_exception')
        print(exception)
        return HttpResponse(exception)


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD2 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD2 process_view')

    def process_exception(self, request, exception):
        print('MD2 process_exception')
        print(exception)

###视图函数中加入一条错误 ,让process_exception捕获 ,

MD1 process_request
MD2 process_request
MD1 process_view <function presslist at 0x03BAC078>
MD2 process_view
MD2 process_exception
invalid literal for int() with base 10: 'ok'
MD1 process_exception
invalid literal for int() with base 10: 'ok'
MD2 process_response
MD1 process_response

  5)process_template_response(self,request,response)

    参数: wsgi返回的request对象

    执行时机: 视图函数执行返回Templateresponse对象才会执行

    执行顺序: 根据setting注册顺序倒序执行 ,如果设置了多个该类型中间件结果会是最后一个

    返回值: response对象(Templateresponse对象)

    Templateresponse对象: 这个对象使用与render相似 ,但是render最终返回的也是Httpresponse对象 ! 目前两个对象区别就在于templateresponse可以在中间件进行修改

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse


class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MD1 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD1 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD1 process_view', view_func)

    def process_exception(self, request, exception):
        print('MD1 process_exception')
        print(exception)
        return HttpResponse(exception)

    def process_template_response(self, request, response):
        response.context_data = {'author': 'ggg'}
        print('MD1 process_template_response')
        return response


##middle/middles.py 指定templateresponse返回的数据
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2 process_request')
        # return HttpResponse('拒绝访问')

    def process_response(self, request, response):
        print('MD2 process_response')
        # return HttpResponse('拒绝访问')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD2 process_view')

    def process_exception(self, request, exception):
        print('MD2 process_exception')
        print(exception)

    def process_template_response(self, request, response):
        response.context_data = {'author': '7777'}
        print('MD2 process_template_response')
        return response

##视图函数返回编程templateresponse对象
from django.template.response import TemplateResponse

def presslist(request):
    msg_all = models.presslist.objects.all()
    return TemplateResponse(request, 'cbs.html', {'msg': msg_all, 'author': 'qgw'})

 

5.session使用中间件优化

  将校验的session的过程放到process_request中

    1.如果客户端没有cookie存储的sessionid则跳转到login函数

    2.如果用户访问login函数那么就不需要cookie

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse, reverse, redirect, HttpResponseRedirect


class MD1(MiddlewareMixin):
    """缺陷是如果login函数能跳过中间件就好了"""
    def process_request(self, request):
        if not request.session.get('auth') and request.path_info != reverse('tlogin'):
            nowurl = request.path_info
            url = reverse('tlogin') + '?next={}'.format(nowurl)
            if nowurl == reverse('tlogin'):
                url = reverse('tlogin')
            return redirect(url)

 

解析csrf安全的中间件

 

posted @ 2019-09-29 14:33  屈冠文  阅读(110)  评论(0编辑  收藏  举报