neutron源码学习基础知识储备之WSGI
WSGI的全称是Web Server Gateway Interface,翻译过来就是Web服务器网关接口。具体的来说,WSGI是一个规范,定义了Web服务器如何与Python应用程序进行交互,使得使用Python写的Web应用程序可以和Web服务器对接起来。WSGI一开始是在PEP-0333中定义的,最新版本是在Python的PEP-3333定义的。
为什么需要WSGI规范?
在Web部署的方案上,有一个方案是目前应用最广泛的:
首先,部署一个Web服务器专门用来处理HTTP协议层面相关的事情,比如如何在一个物理机上提供多个不同的Web服务(单IP多域名,单IP多端口等)这种事情。
然后,部署一个用各种语言编写(Java, PHP, Python, Ruby等)的应用程序,这个应用程序会从Web服务器上接收客户端的请求,处理完成后,再返回响应给Web服务器,最后由Web服务器返回给客户端。
要采用这种方案,Web服务器和应用程序之间就要知道如何进行交互。为了定义Web服务器和应用程序之间的交互过程,就形成了很多不同的规范。比如改进CGI性能的FasgCGI,Java专用的Servlet规范,还有Python专用的WSGI规范等。提出这些规范的目的就是为了定义统一的标准,提升程序的可移植性。在WSGI规范的最开始的PEP-333中一开始就描述了为什么需要WSGI规范。
WSGI存在的目的有两个:
让Web服务器知道如何调用Python应用程序,并且把用户的请求告诉应用程序。
让Python应用程序知道用户的具体请求是什么,以及如何返回结果给Web服务器。
WSGI中的角色?
在WSGI中定义了两个角色,Web服务器端称为server或者gateway,应用程序端称为application或者framework(因为WSGI的应用程序端的规范一般都是由具体的框架来实现的)。我们下面统一使用server和application这两个术语。
server端会先收到用户的请求,然后会根据规范的要求调用application端,如下图所示:
调用的结果会被封装成HTTP响应后再发送给客户端。
WSGI中间件 ?
WSGI Middleware(中间件)也是WSGI规范的一部分。上一章我们已经说明了WSGI的两个角色:server和application。那么middleware是一种运行在server和application中间的应用(一般都是Python应用)。middleware同时具备server和application角色,对于server来说,它是一个application;对于application来说,它是一个server。middleware并不修改server端和application端的规范,只是同时实现了这两个角色的功能而已。
1.Server收到客户端的HTTP请求后,生成了environ_s,并且已经定义了start_response_s。
2.Server调用Middleware的application对象,传递的参数是environ_s和start_response_s。
3.Middleware会根据environ执行业务逻辑,生成environ_m,并且已经定义了start_response_m。
4.Middleware决定调用Application的application对象,传递参数是environ_m和start_response_m。Application的application对象处理完成后,会调用start_response_m并且返回结果给Middleware,存放在result_m中。
5.Middleware处理result_m,然后生成result_s,接着调用start_response_s,并返回结果result_s给Server端。Server端获取到result_s后就可以发送结果给客户端了。
从上面的流程可以看出middleware应用的几个特点:
Server认为middleware是一个application。
Application认为middleware是一个server。
Middleware可以有多层。
WSGi示例代码?
在给出示例代码前我们需要了解wsgiref,它是官方给出的一个实现了WSGI标准用于演示用的简单Python内置库,实现了一个简单的WSGI Server和WSGI Application(在simple_server模块中),主要分为五个模块:simple_server, util, headers, handlers, validate。
注意:simple_server只支持单线程,做测试
WSGI对于应用程序有以下标准规定:
应用程序必须是一个可调用的对象,因此,应用程序可以是一个函数,一个类,或者一个重载了call的类的实例。
应用程序必须接受两个参数并且要按照位置顺序,分别是environ(环境变量),以及start_response函数(负责将响应的status code,headers写进缓冲区但不返回给客户端)。
应用程序返回的结果必须是一个可迭代的对象
由简入繁
|
|
|
|
|
|
|
|
源码wsgiref解析?
wsgiref.simple_server 中make_server函数
|
|
make_server函数默认使用的服务器类为WSGI Server,调用了构造函数(但是它的构造函数到底藏在哪一层服务器上呢?),相对应的使用WSGIRequestHandler 类作为请求的处理类(这两个类都定义在wsgiref.simple_server模块中),在实例化一个WSGI Server后设置它的application后返回该实例。
server_class=WSGIServer
WSGI Server作为一个服务器,自然免不了要调用socket来建立TCP连接,因此这里的WSGI Server是基于Python的内置网络库BaseHTTPServer.py以及SocketServer.py实现的。
WSGI Server继承了HTTPServer,HTTPServer继承了TCPServer,TCPServer继承了BaseServer,在
BaseServerr中有handle_request函数
|
|
|
|
|
|
关于使用select解决EINTR错误请参考这里:PEP 475 – Retry system calls failing with EINTR
因为我们把timeout设置为None,导致select.select永远不会超时,因此如果一直没有客户端连接服务器,服务器就会阻塞在select函数。当一个EINTR错误提出时,select可以重复调用。
通过select函数当我们确认已经收到了来自客户端的请求连接,此时调用accept函数不会阻塞时,于是调用handle_request_noblock函数,在函数中再依次调用了verify_request, process_request, finish_request。
|
|
handle_request——->handle_request_noblock——–>get_request——–>verify_request——->
process_request———>finish_request———>RequestHandlerClass
RequestHandlerClass在simple_server 传入的是WSGIRequestHandler
handler_class=WSGIRequestHandler
RequestHandlerClass主要用于处理请求,生成一些必要的环境参数之后才传给负责发送响应请求的ServerHandler
WSGIRequestHandler的handle()继承如下,最后追踪到wsgiref/handles.py:BaseHandler
|
|
ServerHandler函数主要功能集中在run函数上,同时start_response函数也定义在同一文件中,start_response函数(在application中调用)也必须要按照PEP-333标准定义
最终所有的数据都在finish_response()中写回给客户端。finish_response函数调用了write函数,write函数每次调用时都会检查headers是否已发送,否则先发送headers在发送data。
start_response函数源码
|
|
start_response函数主要用于检测headers是不是已经发送了,如果发送了必须提出异常,同时检测headers是否有不规范的地方,最后返回一个write函数(用于向套接字相关文件写入数据,PEP要求)。
参考:
https://segmentfault.com/a/1190000003069785
http://blog.csdn.net/laughing2333/article/details/51288660