Tornado 之WSGI
WSGI毕竟是Python社区官方认可的规范,可是这种规范在多线程多进程模式下实现很简单,不太适合单线程异步这种情况。鉴于此Tornado并没有按照这个框架去实现一个WSGI的web框架,可是它却提供了基本的兼容,1.允许Tornado的application对象转变成WSGI application。2. 允许WSGI application在tornado ioloop中执行,只是这一切都不是完美的,它仅仅提供了基本的兼容,效率和可用性得不到保证。因此个人还是感觉很鸡肋的
回顾WSGI
wsgi由PEP333开始,在PEP3333得到增强。分为两部分,一部分为容器,另一部分为应用。应用的最简形式如下
传入environ基础环境字典(必须包含一些值)和回调函数,最终返回一个可迭代对线
1 | def simple_app(environ, start_response): |
对于容器。则是每接收到一个http请求则调用一次应用。这样的好处是容器和应用可以完全隔离,应用可以使用任意容器来执行
Tornado application转变成WSGI application
实现效果如下
1 | import tornado.web |
在Tornado里面application接受一个参数调用,传入Requests对象。调用的结果是最终生成header以及handler._write_buffer对象(会触发iostream的写事件,最终由IOLoop触发socket写操作)。因此虽然它执行了RequestsHandler._execute操作,实际并没有发生socket发送操作,我们可以从handler对象取得完整的HTTP回复报文。然后调用start_response和返回一个可迭代对象
可以看到重点就是从WSGI server传递的environ字典里面重组出一个Request对象(模拟到和httpserver模块中的HTTPRequest对象一样)
1 | class WSGIApplication(web.Application): |
可以看到重点就是从environ里面构建出一个兼容httpserver的HTTPRequest对象。另外由于IOLoop在这种情况下不允许使用,所以依赖IOLoop的异步特性也就不存在了。而且连同多线程的特性也不在存在。所以只是一个玩具罢了吧
在Tornado中运行WSGI application
上面的是将tornado的应用转变成WSGI兼容,然后让WSGI的容器去运行。这一个是反过来,让tornado作为容器去运行WSGI应用。实现这样的效果
1 | def simple_app(environ, start_response): |
tornado.httpserver.HTTPServer会调用函数并传入一个Request对象。刚好和上面的过程相反。将Request对象分割为environ
和start_response
。直接贴1.0.0的原始代码吧
1 | class WSGIContainer(object): |
主要是将Requests转变成environ,传入给WSGI应用。最终根据应用的返回重组成一个HTTP回复报文字符串调用发送逻辑,流程完成。