Django的中间件以及Request/Response循环

Django的中间件以及Request/Response循环

前言:萌新的疑问

在建立一个新的Django项目时,你要做的第一件事就是连接你的URLconf并设置一些视图。 但是这里真的发生了什么? Django如何将流量路由到视图,中间件在这个周期中扮演什么角色?
我以前眼中的Django:

image

WSGI

WSGI是为解决一个基本问题而创建的工具:将Web服务器连接到Web框架。 WSGI有两个方面:'服务器'方面和'应用程序'方面。 为了处理WSGI响应,服务器执行应用程序,并向应用程序端提供回调函数。 应用程序处理请求并使用提供的回调将响应返回给服务器。 本质上,WSGI处理程序充当您的Web服务器(Apache,NGINX等)和您的Django项目之间的守门员。

服务器和应用程序之间是中间件。 您可以将中间件视为一系列双向过滤器:它们可以改变(或短路)在网络和Django应用程序之间来回传输的数据。

整个Django的执行过程:数据流

当用户请求你的应用程序时,WSGI处理程序被实例化,然后Django按照顺序处理以下环节:

  1. 导入你的settings.py文件和Django的异常类。
  2. 加载它在位于settings.py中的MIDDLEWARE_CLASSES或者。MIDDLEWARES(取决于Django版本)元组中找到的所有中间件类。
  3. 构建处理 requestview, responseexception的四个方法列表。
  4. 通过请求方法循环,按顺序运行它们。
  5. 解决了所请求的URL。
  6. 循环每个视图处理方法。
  7. 调用视图函数(通常是渲染模板)。
  8. 处理任何异常方法。
  9. 循环遍历每个响应方法(从内向外,从请求中间件的相反顺序)。
  10. 最后建立一个返回值并调用web服务器的回调函数。

中间件

中间件被用在Django项目中的许多关键功能中:例如,使用CSRF中间件来防止跨站请求伪造攻击。 他们用来处理会话数据。 身份验证和授权是使用中间件完成的。 您可以编写自己的中间件类来通过应用程序调整(或短路)数据流。

image

process_request

Django中间件必须至少包含以下方法之一:process_requestprocess_responseprocess_viewprocess_exception。 这些是由WSGI处理程序收集的方法,然后按列出的顺序调用。 让我们快速浏览django.contrib.auth.middleware.AuthenticationMiddleware,这是运行django-admin.py startproject时默认安装的中间件之一:

def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user


class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
              "The Django authentication middleware requires session middleware "
              "to be installed. Edit your MIDDLEWARE%s setting to insert "
              "'django.contrib.sessions.middleware.SessionMiddleware' before "
              "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
        request.user = SimpleLazyObject(lambda: get_user(request))

正如你所看到的,这个中间件只能处理来自Django应用程序的数据流的“请求”步骤。 该中间件首先验证会话中间件是否已经被使用,然后通过调用get_user帮助函数来设置用户。 当WSGI处理程序迭代process_request方法列表时,它会构建这个请求对象,最终将被传递到视图中,并且您将能够引用request.user。 settings.py中有一些中间件没有有process_request方法。 不过没关系,在这个阶段刚刚被跳过。

process_request应该返回None(如本例),或者可以返回一个HttpResponse对象。 在前一种情况下,WSGI处理程序将继续处理process_request方法,后者将“短路”进程并开始process_response循环。【如上图所示,跳过view过程,直接去response】

Resolve the URL(解析URL)

现在process_request方法已经被调用了,现在我们有一个请求对象将被传递给视图。在此之前,Django必须解析URL并确定调用哪个视图函数。这只是通过正则表达式匹配来完成的。您的settings.py将会有一个名为ROOT_URLCONF的键,它表示“root”urls.py文件,您将从中为每个应用程序添加urls.py文件。 URL路由在Django教程中已经非常广泛地介绍了,所以在这里就不需要了。

一个观点有三个要求:

  1. 它必须是可调用的。它可以是基于函数的视图,也可以是继承自基于类的视图。根据HTTP动作(GET,POST等)查看as_view() 方法以使其可调用。
  2. 它必须接受一个HttpRequest对象作为第一个位置参数。这是调用所有process_request和process_view中间件方法的结果。
  3. 它必须返回一个HttpResponse对象,或引发一个异常。这是用于启动WSGI处理程序的process_view循环的响应对象。

process_view

现在WSGI处理程序知道要调用哪个视图函数,它再次遍历其中间件方法列表。 任何Django中间件的process_view方法都是这样声明的:

process_view(request,view_function,view_args,view_kwargs)

和process_request一样,process_view函数必须返回None或HttpResponse对象(或引发异常),从而允许WSGI处理程序继续处理视图或“短路”并返回响应。 查看CSRF中间件的源代码,查看process_view的实例。如果存在CSRF cookie,那么process_view方法将返回None并执行视图。 如果不是,请求被拒绝,并且进程被短路,导致失败消息。

process_exception

如果view函数产生一个异常,Handler将遍历它的process_exception方法列表。 这些方法以相反的顺序执行,从settings.py中列出的最后一个中间件到第一个。 如果发生异常,则进程将短路,并且不会调用其他进程中断件。 通常我们依靠Django的BaseHandler提供的异常处理程序,但是在编写自己的定制中间件类时,您当然可以实现自己的异常处理。

process_response

在这一点上,我们将有一个HttpResponse对象,可以是由视图或由WSGI处理程序构建的process_view方法列表返回的,也可以轮流循环访问响应中间件。这是任何中间件都必须修改数据的最后机会,并且是从内层向外执行的(想象一下洋葱,视图在中心)。看一下缓存中间件源代码中的process_response实例:取决于应用程序中的不同条件(即缓存是否关闭,如果我们正在处理流等),我们需要响应存储在缓存中还是不存在。

注意:在1.10之前的Django和更高版本之间的一个区别是:在旧式MIDDLEWARE_CLASSES中,即使较早的中间件使进程短路,每个中间件也将始终调用其process_response方法。在新的MIDDLEWARES风格中,只有中间件和之前执行的中间件才会调用其process_response方法。有关MIDDLEWARES和MIDDLEWARE_CLASSES之间差异的更多详细信息,请参阅文档。

好了~

最后,Django的WSGI Handler从HttpResponse对象构建一个返回值,并执行回调函数将该数据发送到Web服务器并发送给用户。

所以,两个关键要点:

  1. 现在我们知道view函数是如何与URLconf相匹配的,以及实际调用的是什么(WSGI Handler)。
  2. 有四个关键点可以通过您自己的定制中间件进入请求/响应循环:process_request,process_response,process_view和process_exception。 想一想:请求中间件是从外部执行的,在中心点击查看,然后通过响应中间件返回到表面。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Refer to: www.threemeal.com/blog/12/ 中间件 中间件是一个钩子框架,它们可以介...
    兰山小亭阅读 16,465评论 9 165
  • 目录 一、中间件简介 在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合...
    CaiGuangyin阅读 756评论 0 3
  • Django 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。交流群:467338606网站:h...
    布客飞龙阅读 774评论 0 37
  • 中间件是一个钩子框架,它们可以介入Django 的请求和响应处理过程。它是一个轻量级、底层的“插件”系统,用于在全...
    低吟浅唱1990阅读 514评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139