WSGI -- 网关接口

引子

网关接口在服务器和应用中间承担一个“翻译官”的角色。只要应用程序符合网关接口的标准,那么服务器就只要做好服务器的角色,应用程序只要做好应用程序的作用,服务器和应用程序之间的通信全靠网关接口来协调。常用的网关接口有CGIWSGI,本文就以WSGI网关接口来对此进行说明。

 

WSGI网关接口

WSGI (Python Web Server Gateway Interface, Python Web服务器网关接口)是一个Web服务器和Web应用程序之间的标准化接口,用于增进应用程序在不同的Web服务器和框架之间的可移植性。关于该标准的官方说明可以参考PEP333

 

WSGI的主要作用是在Web服务器和Web应用程序承担“翻译官”的角色。对于这一角色可以这样理解:

  1. Web服务器的责任在于监听和接收请求。在处理请求的时候调用WSGI提供的标准化接口,将请求的信息转给WSGI

  2. WSGI的责任在于“中转”请求和响应信息。WSGI接收到Web服务器提供的请求信息后可以做一些处理,之后通过标准化接口调用Web应用,并将请求信息传递给Web应用。同时,WSGI还将会处理Web应用返回的响应信息,并通过服务器返回给客户端;

  3. Web应用的责任在于接收请求信息,并且生成响应。

根据以上分析,要实现符合WSGI标准的Web服务,服务器和应用程序的设计就要符合WSGI规范。

 

WSGI规范

WSGI规范如下:

  • 服务器的请求处理程序中要调用符合WSGI规范的网关接口;

  • 网关接口调用应用程序,并且要定义start_response(status, headers)函数,用于返回响应;

  • 应用程序中实现一个函数或者一个可调用对象webapp(environ, start_response)。其中environ是环境设置的字典,由服务器和WSGI网关接口设置,start_response是由网关接口定义的函数。

在Python标准库中,wsgiref包就是符合WSGI标准的Web服务实现。后面简单对wsgiref包进行介绍,以此来对符合WSGI标准的Web服务的实现过程进行梳理。

 

wsgiref包

wsgiref包为实现WSGI标准提供了一个参考,它可以作为独立的服务器测试和调试应用程序。在实际的生产环境中尽量不要使用。wsgiref包含有以下模块:

  • simple_server模块 ——simple_server模块实现了可以运行单个WSGI应用的简单的HTTP服务器。

  • headers模块 ——管理响应首部的模块。

  • handlers模块 ——符合WSGI标准的Web服务网关接口实现。该模块包含了一些处理程序对象,用来设置WSGI执行环境,以便应用程序能够在其他的Web服务器中运行。

  • validate模块 ——“验证包装”模块,确保应用程序和服务器都能够按照WSGI标准进行操作。

  • util模块 ——一些有用的工具集。

以上模块暂时不做详细的介绍。本文剩余内容将simple_server模块单独拿出来,以其中的测试例子简单说明符合WSGI标准的Web服务器的实现过程。

 

simple_server——一个简单的符合WSGI规范的服务器

wsgiref包的simple_server模块实现了一个符合WSGI规范的服务器。测试代码如下:

1
2
3
4
5
6
7
8
if __name__ == '__main__':
httpd = make_server('', 8000, demo_app)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
import webbrowser
webbrowser.open('http://localhost:8000/xyz?abc')
httpd.handle_request() # serve one request, then exit
httpd.server_close()

1. 创建HTTP服务器

上述测试代码中httpd = make_server('', 8000, demo_app)创建了一个HTTP服务器。

其中make_server函数用来创建服务器:

1
2
3
4
5
6
7
def make_server(
host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
):
"""Create a new WSGI server listening on `host` and `port` for `app`"""
server = server_class((host, port), handler_class)
server.set_app(app)
return server

make_server函数使用WSGIServer类构建符合WSGI规范的HTTP服务器,使用WSGIRequestHandler类作为处理请求的类,使用demo_app作为一个Web应用。该函数返回一个服务器实例,并开始监听请求。可以通过httpd.socket.getsockname()获取服务器地址和端口号。

2. 使用webbrowser模块创建请求

紧接着,测试例子导入webbrowser模块,使用函数创建了一个请求。

1
webbrowser.open('http://localhost:8000/xyz?abc')

3. 服务器处理请求

服务器通过handle_request()方法处理请求。关于处理请求的过程简单介绍如下:

  • handle_request()方法通过调用get_requestverify_requestprocess_requestfinish_request等方法创建一个请求处理实例(该过程可以参考TCPServer、HTTPServer的实现过程);

  • 请求处理实例调用handle()方法处理请求。handle()WSGIRequestHandler类中进行了重写。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def handle(self):
"""Handle a single HTTP request"""
 
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
 
if not self.parse_request(): # An error code has been sent, just exit
return
 
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())

上面handle()函数先解析了请求,之后创建了一个WSGI网关类实例handler,这个实例可以作为服务器和应用程序之间的接口存在。

4. WSGI网关的请求处理过程

WSGI网关的定义在handlers模块。上一步骤中通过调用WSGI网关类实例handlerrun方法,WSGI网关开始处理请求。

run方法的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous servers shouldn't
# call close() from finish_response(), so if you close() anywhere but
# the double-error branch here, you'll break asynchronous servers by
# prematurely closing. Async servers must return from 'run()' without
# closing if there might still be output to iterate over.
try:
self.setup_environ()
self.result = application(self.environ, self.start_response)
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just give up already!
self.close()
raise # ...and let the actual server figure it out.

run方法的主要功能有:

  • 通过setup_environ()方法创建WSGI相关的环境;

  • 调用WSGI应用的函数或者WSGI应用的可调用对象。本测试例子中的WSGI应用是一个简单的函数,其作用是将请求的environ信息打印出来。

  • 调用finish_response()方法将WSGI应用返回的数据作为响应发回。

5. 关闭服务器

请求结束后,服务器会调用一系列函数关闭请求连接。之后测试代码调用server_close()方法关闭服务器。

 

博客转自:http://fanchunke.me/Python/wsgiref%E5%8C%85%E2%80%94%E2%80%94%E7%AC%A6%E5%90%88WSGI%E6%A0%87%E5%87%86%E7%9A%84Web%E6%9C%8D%E5%8A%A1%E5%AE%9E%E7%8E%B0%EF%BC%88%E4%B8%80%EF%BC%89/

 




WSGI初探及wsgiref 原理流程 : http://blog.csdn.net/laughing2333/article/details/51288660

 

 

 

 

 

 

posted @ 2018-03-22 19:49  JAYWX  阅读(184)  评论(0编辑  收藏  举报