中间件:

在研究中间件的时候我们首先要知道

1 什么是中间件?

官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

2 中间件的作用?

中间件主要就是用于在全局范围内改变Django的输入和输出。一个请求过来在进行处理之前要先经过中间件,同时相应的时候也要经过中间件。

3 Django中的中间件我们可以通过查看settings中的MIDDLEWARE:

那么看到这个我们知道我们最开始的时候在不注释掉   ====》'django.middleware.csrf.CsrfViewMiddleware',    这一句的时候,我们的请求有时候会有一个大黄页:forbidden。。。等这些内容,那么这个时候我们其实就可以解释为什么了:

csrf_token,当我们使用浏览器访问一个服务器的时候如果没有携带csrf_token那么相当于这个网站是不安全的,那么服务器是不会对你的请求进行相应的,也就返回给你一个forbidden。

那么下面我们通过一个图来看下中间件在Django中的位置:

 自定义中间件:

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

process_request(self,request)   #在urls之前处理请求。
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) #在视图函数之后进行相应。

以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

那么一般情况下我们主要是用的是:

process_request(self,request)

process_response(self, request, response)
那么从这个两个函数的的参数,我们可以知道,一般情况下request是不需要返回值的,因为如果他有返回值的话,我们的请求直接就在中间件就给他返回了,而没有经过我们的一个视图函数。
而response是需要返回值的,因为他是按照列表倒序执行的,那么下一步的操作需要上一步的返回值才能继续进行操作,不然会报错。

中间件五大方法:

1   中间件process_request(self,request)

process_request有一个参数,就是request,这个request和视图函数中的request是一样的。

它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。

我么可以新创建一个py文件,也可以在一个package里面创建,只要我们在settings里的MIDDLEWARE中添加进去就可以。
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Middleware1(MiddlewareMixin):
def process_request(self, request):
print('这是中间件middle1!!!')
# return HttpResponse('中间件request的返回值') class Middleware2(MiddlewareMixin):
def process_request(self, request):
print('这是中间件middle12!!')

那么这个时候我们再通过浏览器访问的时候,pycharm的终端中就会打印相应的消息,我们通过这个可以的出结论:

1 中间件的process_request方法是在执行视图函数之前执行的。
2 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
3 不同中间件之间传递的request都是同一个对象

2  中间件process_response(self, request, response)

它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。

那么我们在1   process_request(self,request)的基础上再添加类与方法:

from django.utils.deprecation import MiddlewareMixin
from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import HttpResponse

class Middleware1(MiddlewareMixin):
def process_request(self, request):
print('这是中间件middle1!!!')
# return HttpResponse('中间件request的返回值')
   def process_response(self,request,response)
     print('这是M1的响应')
     return response class Middleware2(MiddlewareMixin):
def process_request(self, request):
print('这是中间件middle12!!')
  
    def process_response(self,request,response)
      print('这是M1的响应')
       return response

那么同样的我们从pycharm终端打印的结果得出结论:

process_response方法是在视图函数之后执行的,并且顺序是MD1比MD2先执行。(此时settings.py中 MD2比MD1先注册)

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,
最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

3 中间件process_view:

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

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

给MD1和MD2添加process_view方法:

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    def process_request(self, request):
print("MD1里面的 process_request") def process_response(self, request, response):
print("MD1里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD1 中的process_view")
print(view_func, view_func.__name__) class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass def process_response(self, request, response):
print("MD2里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD2 中的process_view")
print(view_func, view_func.__name__)

访问index视图函数,看一下输出结果:

MD2里面的 process_request
MD1里面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001DE68317488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001DE68317488> index
app01 中的 index视图
MD1里面的 process_response
MD2里面的 process_response

process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

4 中间件process_exception

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

给MD1和MD2添加上这个方法:

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    def process_request(self, request):
print("MD1里面的 process_request") def process_response(self, request, response):
print("MD1里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD1 中的process_view")
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception)
print("MD1 中的process_exception") class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass def process_response(self, request, response):
print("MD2里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD2 中的process_view")
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception)
print("MD2 中的process_exception")

如果视图函数中无异常,process_exception方法不执行。

想办法,在视图函数中抛出一个异常:

def index(request):
print("app01 中的 index视图")
raise ValueError("呵呵")
return HttpResponse("O98K")

在MD1的process_exception中返回一个响应对象:

class MD1(MiddlewareMixin):

    def process_request(self, request):
print("MD1里面的 process_request") def process_response(self, request, response):
print("MD1里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD1 中的process_view")
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception)
print("MD1 中的process_exception")
return HttpResponse(str(exception)) # 返回一个响应对象

看输出结果:

MD2里面的 process_request
MD1里面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x0000022C09727488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index视图
呵呵
MD1 中的process_exception
MD1里面的 process_response
MD2里面的 process_response

注意,这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。

5  中间件process_template_response(self, request, response)

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

class MD1(MiddlewareMixin):

    def process_request(self, request):
print("MD1里面的 process_request") def process_response(self, request, response):
print("MD1里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD1 中的process_view")
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception)
print("MD1 中的process_exception")
return HttpResponse(str(exception)) def process_template_response(self, request, response):
print("MD1 中的process_template_response")
return response class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass def process_response(self, request, response):
print("MD2里面的 process_response")
return response def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD2 中的process_view")
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception)
print("MD2 中的process_exception") def process_template_response(self, request, response):
print("MD2 中的process_template_response")
return response

views.py中:

def index(request):
print("app01 中的 index视图") def render():
print("in index/render")
return HttpResponse("O98K")
rep = HttpResponse("OK")
rep.render = render
return rep

访问index视图,终端输出的结果:

MD2里面的 process_request
MD1里面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001C111B97488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001C111B97488> index
app01 中的 index视图
MD1 中的process_template_response
MD2 中的process_template_response
in index/render
MD1里面的 process_response
MD2里面的 process_response

从结果看出:

视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

五大方法在Django中的执行流程:

上一部分,我们了解了中间件中的5个方法,它们的参数、返回值以及什么时候执行,现在总结一下中间件的执行流程。

请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。加入中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

那么我们研究过中间件之后我们知道可以使用中间件控制我们的登录验证:

中间件版的登录验证需要依靠session,所以数据库中要有django_session表。

urls.py

from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'^index/$', views.index),
url(r'^login/$', views.login, name='login'),
] urls.py

views.py

from django.shortcuts import render, HttpResponse, redirect

def index(request):
return HttpResponse('this is index') def home(request):
return HttpResponse('this is home') def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd") if user == "Q1mi" and pwd == "":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html") views.py

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>登录页面</title>
</head>
<body>
<form action="{% url 'login' %}">
<p>
<label for="user">用户名:</label>
<input type="text" name="user" id="user">
</p>
<p>
<label for="pwd">密 码:</label>
<input type="text" name="pwd" id="pwd">
</p>
<input type="submit" value="登录">
</form>
</body>
</html> login.html

middlewares.py

class AuthMD(MiddlewareMixin):
white_list = ['/login/', ] # 白名单
balck_list = ['/black/', ] # 黑名单 def process_request(self, request):
from django.shortcuts import redirect, HttpResponse next_url = request.path_info
print(request.path_info, request.get_full_path()) if next_url in self.white_list or request.session.get("user"):
return
elif next_url in self.balck_list:
return HttpResponse('This is an illegal URL')
else:
return redirect("/login/?next={}".format(next_url)) 登录校验中间件

在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',
'middlewares.AuthMD',
] settings.py中注册中间件

AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。

访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;

如果URL在黑名单中,则返回This is an illegal URL的字符串;

正常的URL是需要登录后访问,让浏览器跳转到登录页面。

注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。

Django整体请求流程图:

Django中的中间件(middleware)的更多相关文章

  1. Django 中CSRF中间件 'django.middleware.csrf.CsrfViewMiddleware',

    1.Django中CSRF中间件的工作原理及form表单提交需要添加{% csrf_token %}防止出现403错误 CSRF # 表示django全局发送post请求均需要字符串验证功能:防止跨站 ...

  2. Django 中的中间件

    Django 中的中间件 Django  中间件 中间件介绍 前戏 之前在判断登录的时候使用的是装饰器的功能,通过给视图函数加装饰器来增加判断是否登录的功能.但此方法的缺点是必须给每个需要判断登录的视 ...

  3. Django框架之中间件MiddleWare

    Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健 ...

  4. [Django高级]理解django中的中间件机制和执行顺序

    原文来自 Understanding Django Middlewares, 这篇文章从整体上介绍了django中中间件定义,作用,和怎么样自己写中间件 –orangleliu. 注:middlewa ...

  5. django中的中间件

    中间件介绍 什么是中间件? 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django的输入和输出.每个中间件组件都负责 ...

  6. django中的中间件机制和执行顺序

    这片文章将讨论下面内容: 1.什么是middleware 2.什么时候使用middleware 3.我们写middleware必须要记住的东西 4.写一些middlewares来理解中间件的工作过程和 ...

  7. Django 详解 中间件Middleware

    Django中间件 还是涉及到django的请求生命周期.middle ware 请求穿过中间件到达url,再经过中间件返回给用户. 简单实例 django项目根目录新建一个Middle文件夹,再新建 ...

  8. Django 学习之中间件Middleware

    一.中间件介绍 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响 ...

  9. express中的中间件(middleware)、自定义中间件、静态文件中间件、路由中间件

    express文档地址 什么是中间件呢(middleware)?它是谁的中间件呢? 首先我们需要了解到请求和响应, 请求就是客户端发送请求给服务器, 响应就是,服务器根据客户端的请求返回给客户端的数据 ...

随机推荐

  1. IDEA基本設置

    2.界面字体大小设置 File菜单->Settings->Appearance->Override default fonts by(not recommended):Name:宋体 ...

  2. redis String结构

    1. 设置c的过期时间为100s 2. psetex的单位为毫秒 10000毫秒 3. getrange 获得字符的范围 4. getset 先获得旧的值,然后设置新的值 5. 设置多个值 6. 获得 ...

  3. Spring Cloud(Dalston.SR5)--Eureka 服务消费

    服务被注册.发布到 Eureka 服务器后,需要有程序去发现他,并且进行调用,称为服务消费,一个服务可能会部署多个实例,调用过程可能涉及负载均衡.服务器查找等问题,这些问题 Netflix 项目已经帮 ...

  4. Spring Cloud 快速教程

    官方:http://projects.spring.io/spring-cloud/ 中文:https://springcloud.cc/ https://blog.csdn.net/forezp/a ...

  5. NGINX 资料

    查看资料详情     nginx

  6. C++进阶--拥有资源句柄的类(浅拷贝,深拷贝,虚构造函数)

    // Person通过指针拥有string class Person { public: Person(string name) { pName_ = new string(name); } ~Per ...

  7. Lucene 4.0 正式版发布,亮点特性中文解读[转]

    http://blog.csdn.net/accesine960/article/details/8066877 2012年10月12日,Lucene 4.0正式发布了(点击这里下载最新版),这个版本 ...

  8. dfs常见的配置文件中的value与description(重要)

    不多说,直接上干货! name value description dfs.namenode.logging.level info The logging level for dfs namenode ...

  9. 【IIS错误】IIS各种错误

    IIS简介 当用户试图通过HTTP或文件传输协议(FTP)访问一台正在运行Internet信息服务 (IIS)的服务器上的内容时,IIS返回一个表示该请求的状态的数字代码.该状态代码 记录在IIS日志 ...

  10. mac下面 ,启动2个桌面版appium的方法

    分别打开2个终端,分别输入 appium 就可以分别起2个appium桌面版,然后设置端口 即可 参考: https://blog.csdn.net/qq_15283475/article/detai ...