深入理解Django的中间件middleware

yipeiwu_com5年前Python基础

本文讲述的内容基于 Django 1.11

摘要

Django 中的中间件(middleware),是一个镶嵌到Django的request/response处理机制中的一个hooks框架,是一个修改django全局输入输出的一个底层插件系统。让我们可以自定义想要的一些功能来处理用户的请求。

在Django中,中间件其实就是一个类,在类中包含一组特定的功能,在请求到来或者结束时,Django会根据我们定义的中间件规则执行中间件中对应的方法,一个 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',
]

MIDDLEWARE这里列表中的每一个元素,其实就是一个个单独的中间件,举例来说:django.middleware.csrf.CsrfViewMiddleware这个中间件,作用就是在我们的 form 表单提交请求的时候,提交的时候必须要带上csrf_token,否则就不会正确提交。

中间件使用也需要讲究顺序,下一层依赖上一层的封装,例如,我们的AuthenticationMiddleware是一个认证中间件,在session 中保存认证用户的信息,但是他必须依赖于SessionMiddleware才可以被正确使用,所以他也必须在SessionMiddleware之后。但是具体的顺序问题可以参考这里

中间件结构

中间件类中需要包含以下处理方法:

1. process_request(self, request)
2. process_view(self, request, callback, callback_args, callback_kwargs)
3. process_template_response(self, request, response)
4. process_exception(self, request, exception)
5. process_response(self, request, response)

执行过程

以我们的项目中默认中间件为例子,具体的流程如下所示:

中间件执行前提

中间件要按照一定的顺序一层一层的执行下去,需要按照标准返回特定的内容:

  • 如果为 None,则按照顺序继续向下执行
  • 如果为 HttpResonse 对象,则直接将这个对象返回给用户

此处有一个版本前后的区别,请大家注意区分:

在 Django1.10之后, 当某个中间件,例如CsrfViewMiddleware请求process_request没有返回 None 后,这个请求会交给CsrfViewMiddleware的process_response来返回,即返回给相同一层的中间件来返回:

在 Django1.10之前的版本,会返回到最底层的中间件来返回:

中间件方法:

1、process_request(self, request)

其中request参数就是我们的HttpRequest对象,process_request 会在每个request在被决定使用哪个view之前调用,它会返回None或HttpResponse对象

2、process_view(self, request, callback, callback_args, callback_kwargs)

其中request参数就是的HttpRequest对象,callback 就是请求被决定使用的 view 函数,书具体的函数名,不是字符串类型。callback_args和callback_kwargs是 view 函数需要接受的参数,它会返回None或HttpResponse对象

3、process_template_response(self, request, response)

其中request 是 HttpRequest 对象, response 是一个由Django view或者中间件返回的TemplateResponse 对象,process_template_response()在 view 使用 render 渲染一个模版对象完成之后被调用,它必须返回一个render 方法执行后的response对象。

4、process_exception(self, request, exception)

其中request参数就是的HttpRequest对象,exception是view函数中raise的Exception对象,当 view 函数 raise 一个 exception 的时候调用process_exception,它会返回None或HttpResponse对象

5、process_response(self, request, response)

其中request是 HttpRequest 对象,response 是一个django view或者中间件返回的 HttpResponse 或者StreamingHttpResponse对象,process_response会在所有响应到达浏览器之前被调用

中间件的详细执行流程

由于process_template_response在特定的 rander 渲染中才会被调用,所以过程中不添加该方法

自建中间件与执行过程测试

为了更加清晰的展示中间件的执行过程与如何自定义一个中间件,我们模拟一个简单的用户请求和中间件执行过程:

自定义中间件

from django.utils.deprecation import MiddlewareMixin
class MyMiddleware_1(MiddlewareMixin):
 def process_request(self, request):
  print("自定义 process_request 1")
  return None

 def process_response(self, request, response):
  print("自定义 process_response 1")
  return response

 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定义 process_view 1")
  return None

 def process_exception(self, request, exception):
  print("自定义 process_exception 1")


class MyMiddleware_2(MiddlewareMixin):

 def process_request(self, request):
  print("自定义 process_request 2")
  return None

 def process_response(self, request, response):
  print("自定义 process_response 2")
  return response

 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定义 process_view 2")
  return None

 def process_exception(self, request, exception):
  print("自定义 process_exception 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',
 'app01.middle_by_me.MyMiddleware_1', # 第一个自定义 middleware
 'app01.middle_by_me.MyMiddleware_2' # 第二个自定义 middleware
]

输出结果

自定义中间件应用场景

应用场景这个问题其实不是很好去固定,因为大家在实际使用过程中的需求都不尽相同,所以我简单的举个我可以想到的例子吧。

在不修改业务逻辑源代码的情况下,我可以使用中间件来对用户的访问进行一定的筛选过滤,或者访问控制。还有能想到的更加牛逼的操作是当源站的 CDN,请求穿透源站,middleware 判断请求的内容是否在缓存中,如果在缓存直接返回,而可以不经过业务后端逻辑,是不是很骚~

是不是很像一个所有视图函数的装饰器~~

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对【听图阁-专注于Python设计】的支持。

相关文章

Python for Informatics 第11章之正则表达式(四)

注:以下文章原文来自于Dr Charles Severance 的 《Python for Informatics》 11.3 组合查询和抽取   如果我们想以“X-”字符串开头的行...

Python将多个list合并为1个list的方法

Python将多个list合并为1个list的方法

1、可以使用"+"号完成操作 输出为: [1, 2, 3, 8, 'google', 'com'] 2、使用extend方法 输入相同 3、使用切片 输出相同 PS:len(l1)...

Python 中如何实现参数化测试的方法示例

之前,我曾转过一个单元测试框架系列的文章,里面介绍了 unittest、nose/nose2 与 pytest 这三个最受人欢迎的 Python 测试框架。 本文想针对测试中一种很常见的...

PHP webshell检查工具 python实现代码

1.使用方法:find.py 目录名称 2. 主要是采用python正则表达式来匹配的,可以在keywords中添加自己定义的正则,格式: ["eval\(\$\_POST","发现PH...

浅析Python编写函数装饰器

编写函数装饰器 本节主要介绍编写函数装饰器的相关内容。 跟踪调用 如下代码定义并应用一个函数装饰器,来统计对装饰的函数的调用次数,并且针对每一次调用打印跟踪信息。 class tr...