应用程序入口 WSGIHandler
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 osos.environ.setdefault("DJANGO_SETTINGS_MODULE", "tomato.settings")from django.core.wsgi import get_wsgi_applicationapplication = 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 WSGIHandlerdef 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
应用程序入口 WSGIHandler的更多相关文章
- Django 源码小剖: 应用程序入口 WSGIHandler
		
WSGI 有三个部分, 分别为服务器(server), 应用程序(application) 和中间件(middleware). 已经知道, 服务器方面会调用应用程序来处理请求, 在应用程序中有真正的处 ...
 - [iOS] 使用xib作为应用程序入口 with IDE
		
[iOS] 使用xib作为应用程序入口 with IDE 在「使用xib做为应用程序入口 with Code」这篇文章中,介绍了如何透过写Code的方式,来使用xib做为应用程序的入口.但其实在Xco ...
 - [iOS] 使用xib做为应用程序入口 with Code
		
[iOS] 使用xib做为应用程序入口 with Code 前言 开发iOS APP的时候,使用storyboard能够快速并且直觉的建立用户界面.但在多人团队开发的情景中,因为storyboard是 ...
 - 【转载】MFC 程序入口和执行流程
		
原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32 ...
 - 一个简单的mfc单页界面文件读写程序(MFC 程序入口和执行流程)
		
参考:MFC 程序入口和执行流程 http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 程序MFCFlie ...
 - 开源GUI-Microwindows之程序入口分析
		
**************************************************************************************************** ...
 - MFC 程序入口和执行流程
		
MFC(微软基础类库)以C++类的形式封装了Windows API,给开发者提供了便利,但是初学者常常会疑惑MFC程序的入口在哪里?下面给大家简单介绍一下MFC 程序入口和执行流程. 一 MFC程序执 ...
 - 亲测实验,stm32待机模式和停机模式唤醒程序的区别,以及唤醒后程序入口
		
这两天研究了STM32的低功耗知识,低功耗里主要研究的是STM32的待机模式和停机模式.让单片机进入的待机模式和停机模式比较容易,实验中通过设置中断口PA1来响应待机和停机模式. void EXTI1 ...
 - 小程序入口构造工具&二维码测试工具
		
小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...
 
随机推荐
- C#-TextBox-登录表单password无形---ShinePans
			
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
 - linux_ssky-keygen + ssh-copy-id 无密码登陆远程LINUX主机
			
使用下例中ssky-keygen和ssh-copy-id,仅需通过3个步骤的简单设置而无需输入密码就能登录远程Linux主机. ssh-keygen 创建公钥和密钥. ssh-copy-id 把本地主 ...
 - NEFUOJ 500 二分法+最大流量
			
http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=500 description 在这个信息化的时代.网购成为了最流行的购物方 ...
 - Java设计模式(八)观察者模式 迭代器模式
			
(十五)观察者模式 观察者模式,定义对象间一对多关系,一个对象状态发生改变,全部依赖于它的对象都收到通知而且自己主动更新,观察者与被观察者分开.比如邮件订阅.RSS订阅,假设有更新就会邮件通知你. i ...
 - 用python 爬取网页图片
			
import re import string import sys import os import urllib url="http://tieba.baidu.com/p/252129 ...
 - 继续推荐几款VisualStudio的插件
			
原文:继续推荐几款VisualStudio的插件 继前几天推荐了一款转换vs插件的插件后,借着安装VS2013之际,把我比较喜欢的几个插件继续推荐一下. C# Outline 2013 2013 C# ...
 - DataTable相关操作,筛选,取前N条数据,获取指定列数据
			
DataTable相关操作,筛选,取前N条数据,获取指定列数据2013-03-12 14:50 by Miracle520, 2667 阅读, 0 评论, 收藏, 编辑 1 #region DataT ...
 - C#实现Web文件上传的两种方法
			
1. C#实现Web文件的上传 在Web编程中,我们常需要把一些本地文件上传到Web服务器上,上传后,用户可以通过浏览器方便地浏览这些文件,应用十分广泛. 那么使用C#如何实现文件上传的功能呢?下面笔 ...
 - 日积月累系列之省市选择器(js源码)
			
省市选择器是大家经常用到的, 但网上找的省市选择器都不是很实用,于是自己写了移动端的省市选择器. 界面: 源码结构: 演示地址:http://component.cform.cn/city/ 演示二维 ...
 - Android设备连接Unity Profiler性能分析器
			
Unity提供两种方式让Developer的Android设备连接Profiler进行性能分析: 1.通过wifi,Android设备和计算机处于同一个Wlan中. 2.通过USB ADB 普通情况我 ...