美文网首页
Django中间件看完这篇彻底明白

Django中间件看完这篇彻底明白

作者: amyhy | 来源:发表于2022-03-31 13:38 被阅读0次

    我们在使用python的一些库时,会遇到中间件这个概念,比如scrapy和Django,那么什么是中间件呢?

    什么是中间件

    中间件就是在目标结果之间进行的额外处理过程,在Django中就是request和response之间进行的处理,相对来说实现起来比较简单,但是要注意它是对全局有效的,可以在全局范围内改变输入和输出结果,因此需要谨慎使用,否则不仅会造成难以定位的错误,而且可能会影响整体性能。

    中间件有什么用

    如果想要修改HttpRequest或者HttpResponse,就可以通过中间件来实现。

    • 登陆认证:在中间件中加入登陆认证,所有请求就自动拥有登陆认证,如果需要放开部分路由,只需要特殊处理就可以了。
    • 流量统计:可以针对一些渲染页面统计访问流量。
    • 恶意请求拦截:统计IP请求次数,可以进行频次限制或者封禁IP。

    中间件执行流程

    在Django中自定义中间件是非常简单的,在settings.py中有一个配置项:

    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',
    ]
    

    只要把添加的中间件配置在这里就可以了。每一个中间件都是一个类,多个中间件可以写在同一个文件,也可以在独立文件中。每个中间件可以包含五个方法:

    process_request(self,request)
    process_view(self, request, callback, callback_args, callback_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    process_response(self, request, response)
    
    

    我在网上找到这么一张图片,说明了请求的数据流在Django中间件当中的执行流程

    image.png

    中间件函数执行流程

    • 请求到达中间件后先依次执行每个中间件的process_request函数
    • 然后再依次执行每个中间件的process_view函数,找到我们的视图函数
    • 执行视图函数处理请求数据
    • 如果在上面的过程中出现异常,则依次反方向执行每个中间件的process_exception函数
    • 如果请求包含模板渲染,则依次反方向执行每个中间件的process_template_response函数
    • 最后依次反方向执行每个中间件的process_response函数

    以上这些执行函数将返回None或者HttpResponse对象,如果返回None,则交给下一个中间件的对应函数处理;如果返回HttpResponse对象,则将其返回给用户

    在这些中间件的执行函数中,我们最常用的就是process_request和process_response函数,通常用来在视图函数处理前和视图函数处理后执行一些相应的操作,这个要根据我们的业务需求,选择不同的处理过程。例如:进行登陆认证,因为必须要在视图函数处理前进行认证,我们可以在process_request中处理;携带认证cookies信息,就可以在process_response函数中给response对象增加指定cookies值。

    中间件回调函数执行

    • Request函数:process_request(self, request) 执行时机:当接收到前端请求,并生成request对象,但是仍未解析url,未确定当前要运行的视图函数。 如果返回None,Django将继续处理下一个中间件的request函数;如果返回HttpResponse对象,Django将不再执行其他除process_response以外的所有函数,包括后面的process_request函数其他中间件函数以及视图函数
    • View函数:process_view(self, request, callback, callback_args, callback_kwargs) 执行时机:在执行完所有中间件的process_request函数,并且已经匹配到要执行的视图函数,但是还没有调用视图函数之前。 callback:要执行的视图函数对象(就是我们所写的视图处理函数) callback_args:视图函数的位置参数列表(不包含self和request) callback_kwargs:视图函数的关键字参数 如果返回None,Django将继续处理下一个中间件的request函数;如果返回HttpResponse对象,Django将不再执行其他除process_response以外的所有函数,包括后面的process_request函数其他中间件函数以及视图函数
    • Template函数:process_template_response(self, request, response) 执行时机:只有在视图函数的返回对象中有render方法才会执行,并把render方法的返回值返回给用户。
    • Exception函数:process_exception(self, request, exception) 执行时机:如果在执行过程中出现问题,并且抛出一个未被捕获的异常时才被调用。我们可以用它来捕获请求错误,发送通知或者恢复错误场景。 如果返回None,Django将使用框架内置异常处理,并继续交给下一个exception函数;如果返回HttpResponse对象,Django将不再执行其他除process_response以外的所有函数,并中断异常处理。
    • Response函数:process_response(self, request, response) 执行时机:执行完view函数并生成response之后,几乎是必执行的函数。 返回并且只能必须返回HttpResponse对象,否则会导致HTTP请求中断。

    自定义中间件

    • 创建中间件类
    from django.utils.deprecation import MiddlewareMixin
    
    class MyCustomMiddleware1(MiddlewareMixin):
        def process_request(self, request):
            print('MyCustomMiddleware1')
    
        def process_response(self, request, response):
            print('返回 MyCustomMiddleware1')
            return response
    
    class MyCustomMiddleware2(MiddlewareMixin):
        def process_request(self, request):
            print('MyCustomMiddleware2')
    
        def process_response(self, request, response):
            print('返回 MyCustomMiddleware2')
            return response
    
    • 注册中间件
    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',
        'MyMiddleware.MyCustomMiddleware1',
        'MyMiddleware.MyCustomMiddleware2'
    ]
    

    输出结果:

    MyCustomMiddleware1
    MyCustomMiddleware2
    返回 MyCustomMiddleware2
    返回 MyCustomMiddleware1
    

    系统中间件的用途

    • django.middleware.security.SecurityMiddleware 主要是针对安全访问处理,就是把http请求重定向到https请求
    • django.contrib.sessions.middleware.SessionMiddleware 在Django中我们用的request.session就是在process_request中进行处理的,根据我们在settings中配置的SESSION_COOKIE_NAME变量,从cookies中获取对应的值,从表中查询出session值,创建session对象,赋值给request_session对象。
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)
    

    process_response函数中,给response对象设置SESSION_COOKIE_NAME值和过期时间等。

    response.set_cookie(
       settings.SESSION_COOKIE_NAME,
       request.session.session_key, max_age=max_age,
       expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
       path=settings.SESSION_COOKIE_PATH,
       secure=settings.SESSION_COOKIE_SECURE or None,
       httponly=settings.SESSION_COOKIE_HTTPONLY or None,
       samesite=settings.SESSION_COOKIE_SAMESITE
    )
    
    • django.middleware.common.CommonMiddleware 检测是否允许浏览器类型
    if 'HTTP_USER_AGENT' in request.META:
        for user_agent_regex in settings.DISALLOWED_USER_AGENTS:
            if user_agent_regex.search(request.META['HTTP_USER_AGENT']):
                raise PermissionDenied('Forbidden user agent')
    

    检查是否需要添加/,主要是根据settings中APPEND_SLASH配置

    if self.should_redirect_with_slash(request):
        path = self.get_full_path_with_slash(request)
    else:
        path = request.get_full_path()
    

    在process_response函数中,会判断是否需要把404的请求重新定向到我们需要的页面

    • django.middleware.csrf.CsrfViewMiddleware 这个很明显就是我们Django框架的csrf验证了,主要是process_view中的处理,从函数处理我们可以看到以下几点:
      • request请求中包含csrf_processing_done属性,则不进行csrf验证
      • 视图函数中包含csrf_exempt属性,则不进行csrf验证
      • 如果是GET、HEAD、OPTIONS、TRACE请求,则不进行csrf验证
      • request请求中包含_dont_enforce_csrf_checks属性,则不进行csrf验证
      • https请求头中如果不包含HTTP_REFERER,则拒绝访问
      • 请求头中不包含CSRF_COOKIE,则拒绝访问
      • POST请求中携带csrfmiddlewaretoken参数,如果验证通过就可以访问
      • PUT/DELETE请求头中携带CSRF_HEADER_NAME配置,如果验证通过就可以访问
    • django.contrib.auth.middleware.AuthenticationMiddleware 这个中间件中为我们的request对象添加了user属性,主要是获取session中SESSION_KEY值(settings配置中),从用户表中查询对应主键,得到用户对象,将其付给request.user
    • django.contrib.messages.middleware.MessageMiddleware Django的消息框架,主要是向目标中推送消息内容,在前端可通过以下方式使用

    https://cloud.tencent.com/developer/article/1631561

    相关文章

      网友评论

          本文标题:Django中间件看完这篇彻底明白

          本文链接:https://www.haomeiwen.com/subject/ecqnjrtx.html