1. WSGI概述
2. WSGI相关类图详解
2.1 Server类
2.2 RequestHandler类
2.3 Handler类
2.4 小结
3. WSGI application
4. start_response疑惑
1. WSGI概述
WSGI不是服务器,也不是用于与程序交互的API,更不是真实的代码,而只是定义的接口,其目标是在WEB服务器与WEB框架层之间提供一个通用的标准,减少之间的互操作性并形成统一的调用方式。
那么这个接口到底是什么呢?
根据WSGI的定义,其应用application是可调用的对象,其参数固定为两个:
一个包含所有环境变量的dict对象environ;
另一个也是可调用对象,该对象使用HTTP状态码和返回客户端的HTTP头来初始化响应,同时返回一个可迭代对象的用于组成响应负载。
在这里从一段具体的代码进行讲解,学过python web都知道用下面的这段代码就可以产生一个web应用。
当用浏览器访问http://localhost:8000时会在浏览器看到Hello World字样。
下面将讲解WSGI所涉及的个各类
2. WSGI相关类图详解
wsgiref模块是Python内置了一个WSGI服务器,其方法make_server返回一个包含application的web server,make_server通过传入的server_class(这里默认是WSGIServer)创建一个web server,并设置web server关联的applicaion。咦,这里还有个默认参数handler_class是干嘛用的?我们通过代码一步步分析。
2.1 Server类
首先make_server会调用WSGIServer自socketserver.TCPServer继承的__init__创建实例,这过程会做这几步事情:
创建socket:调用socker.socket()方法
Socket绑定host,port:调用WSGIServer类的server_bind()
建立基本的environment:调用WSGIServer类的setup_environ()
Socket监听端口:调用TCPServer类的server_activate(),其实质也是调用socket.listen()。
以上几步实质上是socket的网络编程,用来建立TCP连接。
注:BaseServer里__init__( self, server_address, RequestHandlerClass)传入的RequestHandlerClass就代表着刚才make_server函数传入的参数
handler_class=WSGIRequestHandler。
5.紧接着设置WSGIServer的application,然后调用的httpd.serve_forever(),它本质上是一个select的I/O模型,当有请求来临时调用_handle_request_noblock()函数来处理请求。
6. _handle_request_noblock()调用get_request()函数获得请求内容request和客户端IP、Port信息client_address,紧接着会调用process_request处理请求
7.process_request会通过调用finish_request()会初始化一个RequestHandlerClass的实例,实质是make_server()函数传入的handler_class=WSGIRequestHandler的作用;这里是调用继承自BaseRequestHandler的__init__()方法。
2.2 RequestHandler类
8.这个初始化BaseRequestHandler过程会调用setup(),setup()函数中最后两行代码要注意,它们的作用是可以像读写文件那样读写socket。
注:SocketServer.StreamRequestHandler中对客户端发过来的数据是用rfile属性来处理的,rfile是一个类file对象.有缓冲.可以按行分次读取;发往客户端的数据通过wfile属性来处理,wfile不缓冲数据,对客户端发送的数据需一次性写入
(引用自http://a564941464.iteye.com/blog/1170464)
9.通过覆盖了的handle()请求进行处理
10.handler()会调用parse_request(),parse_request()代码比较长,这里就不贴出来了,有兴趣的童鞋去trace下代码,它的大致作用是解析http版本,method,path,Conntype(keep-alive)等,如果解析出错会返回False。如果成功,继续执行第11步
2.3 Handler类
11.handler()会调用handler=ServerHandler(self.rfile,stdout, self.get_stderr(), self.get_environ() ),
最后一个参数是通过get_environ()函数获取的,它会将调用WSGIRequestHandler的get_environ(),将3步和第10步的信息放到environ中,也就是最初application(environ,start_response)中传入的environ;然后生成了ServerHandler的实例handler
12.调用handler.run(self.server.get_app());self.server.get_app()是获取我们自己所写的application。
13.调用setup_environ()将WSGI服务器的一些信息放到environ中,这样就将所有的requset信息、server信息保存到environ中。
14.将environ和start_respnse()传给application
15.application调用start_response(),将status,header保存在BaseHandler实例中,并返回一个write函数
16.application将response body返回赋给result变量
17.调用finish_response()将response返回给客户端;我们看到finish_response函数体内是调用write函数,在发送body之前,要判断是否有status值,然后要判断header发出去的吗?如果没有则调用self.send_headers(),最后再发送response body。
2.4 小结
Server类建立基本的Socket连接,然后将请求发送给RequestHandle处理
RequestHandler类解析客户端的Request请求
Handler类设置server、request信息,并交给application
application进行业务的处理,然后由Handler发送response给客户端。
3. WSGI application
1)application必须是一个可调用对象,可调用对象可以是:
函数
类
具有__call__方法的实例
2)同时返回一个可迭代对象
3)接受environ和start_response两个参数
符合上述三点的就是一个WSGI标准的appication,因此这个application可以有以下几种形式
可调用函数
def application(environ, start_response):
return [b'Hello World',]
可调用类
class Application:
def__init__(self,environ, start_response):
pass
def__iter__(self):
yieldb'Hello World'
可调用实例
class ApplicationObj:
def__call__(self,environ, start_response):
return[b'Hello World',]
4. start_response疑惑
WSGI标准规定,start_respnsoe必须返回一个可调用对象,第15步提到start_response返回了一个wirte()函数,于是我们的application还可以这样写
def application(environ,start_response):
write=start_response('200 OK', [('Content-Type','text/html')])
write(‘HelloWorld!’)
return 'What?'
通过浏览器访问得到下面的结果
其实start_response根本没有必要这样,它只要把设置status、header就好了,至于返回response的事情还是让Server去干吧
领取专属 10元无门槛券
私享最新 技术干货