Django 源码小剖: 应用程序入口 WSGIHandler

WSGI 有三个部分, 分别为服务器(server), 应用程序(application) 和中间件(middleware). 已经知道, 服务器方面会调用应用程序来处理请求, 在应用程序中有真正的处理逻辑, 在这里面几乎可以做任何事情, 其中的中间件就会在里面展开.

Django 中的应用程序

任何的 WSGI 应用程序,  都必须是一个 start_response(status, response_headers, exc_info=None) 形式的函数或者定义了 __call__ 的类. 而 django.core.handlers 就用后一种方式实现了应用程序: WSGIHandler.  在这之前, Django 是如何指定自己的 application 的, 在一个具体的 Django 项目中, 它的方式如下:

在 mysite.settings.py 中能找到如下设置:

1
2
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'tomato.wsgi.application'

如你所见, WSGI_APPLICATION 就指定了应用程序. 而按图索骥下去, 找到项目中的 wsgi.py, 已经除去了所有的注释:

1
2
3
4
5
6
import os
 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tomato.settings")
 
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

因此, WSGI_APPLICATION 所指定的即为 wsgi.py 中的全局变量 application. 故伎重演, 继续找下去. 在 django.core 模块中的 wsgi.py 中找到 get_wsgi_application() 函数的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.core.handlers.wsgi import WSGIHandler
 
 
def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Should return a WSGI
    callable.
 
    Allows us to avoid making django.core.handlers.WSGIHandler public API, in
    case the internal WSGI implementation changes or moves in the future.
 
    """
    """
    # 继承, 但只实现了 __call__ 方法, 方便使用
    class WSGIHandler(base.BaseHandler):
    """
    return WSGIHandler()

在 get_wsgi_application() 中实例化了 WSGIHandler, 并无其他操作.

WSGIHandler

紧接着在 django.core.handler 的 base.py 中找到 WSGIHandler 的实现.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 继承, 但只实现了 __call__ 方法, 方便使用
class WSGIHandler(base.BaseHandler):
    initLock = Lock()
 
    # 关于此, 日后展开, 可以将其视为一个代表 http 请求的类
    request_class = WSGIRequest
 
    # WSGIHandler 也可以作为函数来调用
    def __call__(self, environ, start_response):
        # Set up middleware if needed. We couldn't do this earlier, because
        # settings weren't available.
 
        # 这里的检测: 因为 self._request_middleware 是最后才设定的, 所以如果为空,
        # 很可能是因为 self.load_middleware() 没有调用成功.
        if self._request_middleware is None:
            with self.initLock:
                try:
                    # Check that middleware is still uninitialised.
                    if self._request_middleware is None:
                        因为 load_middleware() 可能没有调用, 调用一次.
                        self.load_middleware()
                except:
                    # Unload whatever middleware we got
                    self._request_middleware = None
                    raise
 
        set_script_prefix(base.get_script_name(environ))
        signls.request_started.send(sender=self.__class__) # __class__ 代表自己的类
 
        try:
            # 实例化 request_class = WSGIRequest, 将在日后文章中展开, 可以将其视为一个代表 http 请求的类
            request = self.request_class(environ)
 
        except UnicodeDecodeError:
            logger.warning('Bad Request (UnicodeDecodeError)',
                exc_info=sys.exc_info(),
                extra={
                    'status_code': 400,
                }
            )
            response = http.HttpResponseBadRequest()
        else:
            # 调用 self.get_response(), 将会返回一个相应对象 response
            response = self.get_response(request)
 
        # 将 self 挂钩到 response 对象
        response._handler_class = self.__class__
 
        try:
            status_text = STATUS_CODE_TEXT[response.status_code]
        except KeyError:
            status_text = 'UNKNOWN STATUS CODE'
 
         # 状态码
        status = '%s %s' % (response.status_code, status_text)
 
        response_headers = [(str(k), str(v)) for k, v in response.items()]
 
        # 对于每个一个 cookie, 都在 header 中设置: Set-cookie xxx=yyy
        for c in response.cookies.values():
            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
 
        # start_response() 操作已经在上节中介绍了
        start_response(force_str(status), response_headers)
 
        # 成功返回相应对象
        return response

WSGIHandler 类只实现了 def __call__(self, environ, start_response), 使它本身能够成为 WSGI 中的应用程序, 并且实现 __call__ 能让类的行为跟函数一样, 详见 python __call__ 方法. 从 WSGIHandler 的实现来看, 它并不是最为底层的: WSGIHandler 继承自 base.BaseHandler, 在 django.core.handler 的 base.py 中可以找到: class BaseHandler(object):...

这一节服务器部分已经结束, 接下来的便是中间件和应用程序了, 相关内容会在下节的 BaseHandler 中展开. 我已经在 github 备份了 Django 源码的注释: Decode-Django, 有兴趣的童鞋 fork 吧.

近来准备校园招聘, 生产效率较低, 九月份的空气注定不安分 ;)

捣乱 2013-9-11

http://daoluan.net

 
 
 
标签: 源码剖析, Django

应用程序入口 WSGIHandler的更多相关文章

  1. Django 源码小剖: 应用程序入口 WSGIHandler

    WSGI 有三个部分, 分别为服务器(server), 应用程序(application) 和中间件(middleware). 已经知道, 服务器方面会调用应用程序来处理请求, 在应用程序中有真正的处 ...

  2. [iOS] 使用xib作为应用程序入口 with IDE

    [iOS] 使用xib作为应用程序入口 with IDE 在「使用xib做为应用程序入口 with Code」这篇文章中,介绍了如何透过写Code的方式,来使用xib做为应用程序的入口.但其实在Xco ...

  3. [iOS] 使用xib做为应用程序入口 with Code

    [iOS] 使用xib做为应用程序入口 with Code 前言 开发iOS APP的时候,使用storyboard能够快速并且直觉的建立用户界面.但在多人团队开发的情景中,因为storyboard是 ...

  4. 【转载】MFC 程序入口和执行流程

    原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32 ...

  5. 一个简单的mfc单页界面文件读写程序(MFC 程序入口和执行流程)

    参考:MFC 程序入口和执行流程  http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 程序MFCFlie      ...

  6. 开源GUI-Microwindows之程序入口分析

    **************************************************************************************************** ...

  7. MFC 程序入口和执行流程

    MFC(微软基础类库)以C++类的形式封装了Windows API,给开发者提供了便利,但是初学者常常会疑惑MFC程序的入口在哪里?下面给大家简单介绍一下MFC 程序入口和执行流程. 一 MFC程序执 ...

  8. 亲测实验,stm32待机模式和停机模式唤醒程序的区别,以及唤醒后程序入口

    这两天研究了STM32的低功耗知识,低功耗里主要研究的是STM32的待机模式和停机模式.让单片机进入的待机模式和停机模式比较容易,实验中通过设置中断口PA1来响应待机和停机模式. void EXTI1 ...

  9. 小程序入口构造工具&二维码测试工具

    小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...

随机推荐

  1. [mysql]刷新windows恢复后mysql和"Access denied for user'root'@'IP'"处理问题

    mysql数据库软件实际上是绿色的,重装系统后能够继续使用. 1.重装系统保留原有的后mysql安装文件夹,数据文件夹. 2.制作用于启动一个批处理文件mysql:[run.bat]的文件存储在mys ...

  2. C#5.0新特性

    C#5.0新特性 C#5.0最大的新特性,莫过于Async和Parallel. 以往我们为了让用户界面保持相应,我们可以直接使用异步委托或是System.Threading命名空间中的成员,但Syst ...

  3. PHP的MySQL扩张:MySQL数据库概述

    资源:http://www.ido321.com/1023.html 一.SQL:结构化查询语言 SQL(Structured Query Language)是高级的非过程化变成语言.专门用于查询和改 ...

  4. C#二维码生成解析

    C#二维码生成解析工具,可添加自定义Logo 二维码又称 QR Code,QR 全称 Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的 Bar Code 条形码能 ...

  5. 【Unity 3D】学习笔记四十一:关节

    关节 关节组件能够加入至多个游戏对象中,而加入关节的游戏对象将通过关节连接在一起而且感觉连带的物理效果.须要注意的是:关节必须依赖于刚体组件. 关节介绍 关节一共分为5大类:链条关节,固定关节,弹簧关 ...

  6. POJ 2777 Count Color(线段树+位运算)

    题目链接:http://poj.org/problem?id=2777 Description Chosen Problem Solving and Program design as an opti ...

  7. Android KeyStore Stack Buffer Overflow (CVE-2014-3100)

    /* 本文章由 莫灰灰 编写,转载请注明出处. 作者:莫灰灰    邮箱: minzhenfei@163.com */ 1. KeyStore Service 在Android中,/system/bi ...

  8. js对象字面量

    在编程语言中,字面量是一种表示值的记法.例如,"Hello, World!" 在许多语言中都表示一个字符串字面量(string literal ),JavaScript也不例外.以 ...

  9. STM32W芯片的JTAG口用于GPIO

    使用过程中发现STM32W芯片在驱动液晶SPI液晶时,在调试状态下可以正常工作但在通常运行情况下却没有任何显示! 经查发现我使用的两个端口PC0和PC3的电平很不正常,拉不高. 所以我就怀疑到IO口问 ...

  10. 【分布式存储系统sheepdog 】

    Sheepdog,是由NTT的3名日本研究员开发的开源项目,主要用来为虚拟机提供块设备. 其架构例如以下: 以下,我们将从架构.模块等几个方面来介绍下: 一.架构图 如上图: 採用无中心节点的全对称架 ...