Django应用程序入口WSGIHandler源码解析


Posted in Python onAugust 05, 2019

前言

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 中能找到如下设置:

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

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

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() 函数的实现:

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 的实现.

# 继承, 但只实现了 __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<br>      ############# 关键的操作, self.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__ 方法.

def __call__(self, environ, start_response) 方法中调用了 WSGIHandler.get_response() 方法以获取响应数据对象 response. 从 WSGIHandler 的实现来看, 它并不是最为底层的: WSGIHandler 继承自 base.BaseHandler, 在 django.core.handler 的 base.py 中可以找到: class BaseHandler(object):...

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中super关键字用法实例分析
May 28 Python
Python3如何解决字符编码问题详解
Apr 23 Python
python+matplotlib绘制旋转椭圆实例代码
Jan 12 Python
python3如何将docx转换成pdf文件
Mar 23 Python
Python运维之获取系统CPU信息的实现方法
Jun 11 Python
使用python验证代理ip是否可用的实现方法
Jul 25 Python
python3通过selenium爬虫获取到dj商品的实例代码
Apr 25 Python
Django Sitemap 站点地图的实现方法
Apr 29 Python
Python爬虫谷歌Chrome F12抓包过程原理解析
Jun 04 Python
使用OpenCV获取图片连通域数量,并用不同颜色标记函
Jun 04 Python
Pytorch 卷积中的 Input Shape用法
Jun 29 Python
python实现简单聊天功能
Jul 07 Python
详解如何用TensorFlow训练和识别/分类自定义图片
Aug 05 #Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
Aug 05 #Python
Python获取时间范围内日期列表和周列表的函数
Aug 05 #Python
Django ORM 查询管理器源码解析
Aug 05 #Python
python实现车牌识别的示例代码
Aug 05 #Python
使用python实现滑动验证码功能
Aug 05 #Python
Django 源码WSGI剖析过程详解
Aug 05 #Python
You might like
javascript cookie操作类的实现代码小结附使用方法
2010/06/02 Javascript
基于JQuery的简单实现折叠菜单代码
2010/09/15 Javascript
跨浏览器通用、可重用的选项卡tab切换js代码
2011/09/20 Javascript
Jquery submit()无法提交问题
2013/04/21 Javascript
js jquery获取随机生成id的服务器控件的三种方法
2013/07/11 Javascript
js的image onload事件使用遇到的问题
2014/07/15 Javascript
JS获取当前网页大小以及屏幕分辨率等
2014/09/05 Javascript
JavaScript通过事件代理高亮显示表格行的方法
2015/05/27 Javascript
延时加载JavaScript代码提高速度
2015/12/27 Javascript
简单了解Backbone.js的Model模型以及View视图的源码
2016/02/14 Javascript
jQuery轻松实现表格的隔行变色和点击行变色的实例代码
2016/05/09 Javascript
JS实现颜色动态淡化效果
2017/03/06 Javascript
使用Require.js封装原生js轮播图的实现代码
2017/06/15 Javascript
JS组件系列之Gojs组件 前端图形化插件之利器
2017/11/29 Javascript
微信小程序实现图片懒加载的示例代码
2017/12/13 Javascript
React Native 真机断点调试+跨域资源加载出错问题的解决方法
2018/01/18 Javascript
详解webpack-dev-server的简单使用
2018/04/02 Javascript
Vue-不允许嵌套式的渲染方法
2018/09/13 Javascript
React Hooks的深入理解与使用
2018/11/12 Javascript
vue动态绑定class选中当前列表变色的方法示例
2018/12/19 Javascript
layui 选择列表,打勾,点击确定返回数据的例子
2019/09/02 Javascript
Python的内存泄漏及gc模块的使用分析
2014/07/16 Python
Python基于pillow判断图片完整性的方法
2016/09/18 Python
python+matplotlib绘制3D条形图实例代码
2018/01/17 Python
python爬虫基础教程:requests库(二)代码实例
2019/04/09 Python
用pycharm开发django项目示例代码
2019/06/13 Python
python做接口测试的必要性
2019/11/20 Python
python批量修改文件名的示例
2020/09/27 Python
CSS3 伪类选择器 nth-child()说明
2010/07/10 HTML / CSS
Html5 滚动穿透的方法
2019/05/13 HTML / CSS
Microsoft新加坡官方网站:购买微软最新软件和技术产品
2016/10/28 全球购物
高中生毕业自我鉴定范文
2013/12/22 职场文书
学习雷锋活动总结
2014/04/29 职场文书
工商管理专业自荐信
2014/06/03 职场文书
参赛口号
2014/06/16 职场文书
SQL Server Agent 服务无法启动
2022/04/20 SQL Server