Python的WSGI是什么?

什么是WSGI?

WSGI的全称是Web Server Gateway Interface,即Web服务器网管接口。注意,它不是一个服务器、不是Python模块、不是框架、也不是API程序,它不是任何一种软件,而仅仅是Python语言针对Web服务器和Web应用程序之间通用接口的规范(PEP 3333)。符合WSGI规范的应用程序可以运行在任何符合该规范的Web服务器上。

WSGI规范

WSGI规范十分简单。下面这张时序图展示了WSGI所处的位置,以及调用规则。

1
2
3
4
5
6
Client->Server: request
Note right of Server: WSGI
Server->Application: app_callable(environ, start_response)
Application->Server: start_response(status, response_headers, exc_info=None)
Application->Server: return iterator
Server->Client: response

从上图可见,WSGI处于ServerApplication之间。Server端负责实现start_response这个callbackApplication端负责实现app_callable这个callable对象。
其中,app_callable接受两个参数:

  • environ: 包含有Server提供的所有请求信息的一个dict对象。
  • start_response: Server端提供的回调方法,Application端可以通过它发送HTTP状态码和HTTP头部信息。
    app_callable最后返回一个封装成可迭代对象的响应体字符串。

以下是一个简单的app_callable实现:

1
2
3
4
5
6
7
8
def app_callable(environ, start_response):
response_body = 'Request method: %s' % environ['REQUEST_METHOD']
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]

start_response(status, response_headers)

return [response_body]

WSGIApplication端可以支持堆栈式调用。调用栈中间的Application又被称为MiddlewareMiddleware同时扮演ServerApplication两种角色,因此需要同时实现WSGI两端的接口。
下图是对Middleware所处位置的一个简单表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Note right of Server: WSGI
Server->Application1:
Note right of Application1: WSGi
Middleware1->Application1:
Note right of Middleware1: WSGI
Application1->Middleware2:
Note right of Middleware2: WSGI
Middleware2->Middleware3:
Note right of Middleware3: WSGI
Middleware3->Application2:
Application2->Middleware3:
Middleware3->Middleware2:
Middleware2->Middleware1:
Middleware1->Application1:

WSGI实现示例

在生产环境,一般用Apache+mod_wsgi来作为Server端的标准实现。这里我们使用Python内置的WSGI服务器wsgiref来实现一个简单示例。
编写一个wsgi_test.py文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""test wsgi
"""

# wsgi_test.py

from wsgiref.simple_server import make_server

def application (environ, start_response):
status = '200 OK'
response_headers = [('Content-Type', 'text/plain')]
start_response(status, response_headers)

return [f'Request {environ["REQUEST_METHOD"]}'
f' {environ["PATH_INFO"]} has been'
f' processed\r\n'.encode('utf-8')]

server = make_server('localhost', 8000, application)

# Wait for a single request, serve it and quit
print('Serving HTTP on port 8000...')
server.serve_forever()

接着在命令行运行python wsgi_test.py,启动WSGI服务器。然后打开浏览器,输入http://localhost:8000/ 就可以看到效果了。