专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python爱好者社区  ·  我???这就是信息差吗?F12改成绩,19. ... ·  昨天  
Python爱好者社区  ·  AI ... ·  昨天  
Python中文社区  ·  34万亿“美债危机”黑天鹅要来了?用数据揭晓 ... ·  2 天前  
Python开发者  ·  24 小时不眠不休的 AI 网红,年入 ... ·  4 天前  
Python开发者  ·  DeepSeek 四连炸!梁文峰参与开发 ·  4 天前  
51好读  ›  专栏  ›  Python开发者

Python wsgiref 模块源码浅析

Python开发者  · 公众号  · Python  · 2017-04-05 21:08

正文

(点击 上方蓝字 ,快速关注我们)


来源:人世间(@-人世间-)

www.jianshu.com/p/e7a958bc0f0f

如有好文章投稿,请点击 → 这里了解详情


SimpleHTTPServer模块提供了创建一个http服务的例子。Python web领域里却很少这么做,而是使用了另外一个协议 — WSGI协议。Python的wisgiref模块提供了demo_app,来演示如何使用wsgi协议。


def demo_app ( environ , start_response ) :

from StringIO import StringIO

stdout = StringIO ()

print >> stdout , "Hello world!"

print >> stdout

h = environ . items (); h . sort ()

for k , v in h :

print >> stdout , k , '=' , repr ( v )

start_response ( "200 OK" , [( 'Content-Type' , 'text/plain' )])

return [ stdout . getvalue ()]


demo_app即是一个标准的wsgi app。它接受两个参数,一个包含cgi服务器的环境变量,另外一个参数是一个函数,这个函数也接受两个函数,一个是http状态,另外是http协议的header信息。最后该app返回一个可迭代对象,这个对象即发送给客户端的body内容。demo_app有一些对StringIO的操作,这些都是把environ进行格式化输出。


Python的web框架,都是一个wsgi app。通过自己构造wsgi应用,很容易写出一个框架的骨架。python定义了wsgi,让web框架几乎可以大一统了。下面就来分析,python是如何实现这个协议的。


WSGIServer


python使用WSGIServer和WSGIRequestHandler构建wsgi协议的服务。


class WSGIServer ( HTTPServer ) :

application = None

def server_bind ( self ) :

HTTPServer . server_bind ( self )

self . setup_environ ()

def setup_environ ( self ) :

# 甚至环境变量

env = self . base_environ = {}

env [ 'SERVER_NAME' ] = self . server_name

env [ 'GATEWAY_INTERFACE' ] = 'CGI/1.1'

env [ 'SERVER_PORT' ] = str ( self . server_port )

env [ 'REMOTE_HOST' ] = ''

env [ 'CONTENT_LENGTH' ] = ''

env [ 'SCRIPT_NAME' ] = ''

def get_app ( self ) :

return self . application

def set_app ( self , application ) :

self . application = application


WSGIServer继承HTTPServer,重写了server_bind仿佛,设置了一些专用的环境变量。比较简单,我们也知道,Server只是处理socket连接相关的逻辑,RequestHandler才是处理客户端请求逻辑。


WSGIRequestHandler


WSGIRequestHandler 也不复杂,只有3个方法,get_environ用来设置并返回环境变量的字典,get_stderr用于获取标准错误输出。handle则是重写基类BaseRequestHandler的方法。前文我们也提到,handle用于不同协议处理客户端的入口。


handler


def handle ( self ) :

self . raw_requestline = self . rfile . readline ()

if not self . parse_request () :

return

handler = ServerHandler (

self . rfile , self . wfile , self . get_stderr (), self . get_environ ()

)

handler . request_handler = self

handler . run ( self . server . get_app ())


handle方法和BaseHTTPRequestHanler的handle方法所做的类似,解析验证客户端的http的request是否合法。不同的在于,此时会绑定一个ServerHandler的实例对象,并把缓冲可读可写文件句柄,环境变量等传入该类。同时调用这个对象的run方法。其实,我们之前定义的app,恰恰就是传给run方法,通过run方法的包装,实现wsgi协议的通信。


BaseHandler 和 ServerHandler


ServerHandler 来自wsgiref的handlers模块,它继承 BaseHandler类。又一个带base类。BaseHandler主要用于操作WSGI app。run方法就是在该类定义的。


def run ( self , application ) :

try :

self . setup_environ ()

self . result = application ( self . environ , self . start_response )

self . finish_response ()

except :

try :

self . handle_error ()

except :

self . close ()

raise


run方法最重要的就是调用自定义的wsgi app,并把在finish_reponse方法中把结果send给客户端。


finish_response


def finish_response ( self ) :

try :

if not self . result_is_file () or not self . sendfile () :

for data in self . result :

self . write ( data )







请到「今天看啥」查看全文