WSGI的全称是Web Server Gateway Interface,是Python的一套规范PEP 3333。它定义了web应用怎么跟web server交互,以及多个web 应用怎么串在一起来协力处理一个请求。

Frameworks that run on WSGI¶列举了一堆以WSGI为基础的Python Web框架。

Servers which support WSGI¶列举了支持WSGI的Web服务器。

本文是对PEP 3333的解读。

WSGI定义了三类角色

  • server/gateway,简称s/g
  • application/framework,简称a/f
  • middleware,简称mw

Web服务主要是由request/response构成。对于request,其正常处理的流向有下面几种:

request --> s/g --> a/f
request --> s/g --> mw1 --> ... --> mwN --> a/f

反过来,对于response,可以有:

response <-- s/g <-- a/f
response <-- s/g <-- mw1 <-- ... <-- mwN <-- a/f

设置上WSGI需要a/f侧提供一个callable(函数,或者带有__call__方法的对象,或者是带有__init__的类对象)给s/g侧,来初始化服务。

这个callable代表a/f侧,并接受两个参数,一个是environ,带有环境参数;另一个是start_reponse方法,用来开始输出response。示例如下:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return [HELLO_WORLD]

environ中必须带有WSGI定义的强制参数(跟CGI的环境参数类似)。start_reponse的类型如下:

def start_response(status, response_headers, exc_info=None)

主要是用来传reponse内容体之前发送信息头。s/g侧所要做的就是,对于每个进来的request,调用a/f侧提供的callable。

mw要做的就是同时模拟s/g侧和a/f侧,把两侧链接起来。

从Python3开始,str表示的是Unicode字符,而不是简单的字节。HTTP协议一般是按照字节来处理消息的,要注意转换。

start_response的第一次参数是用来只是HTTP状态吗,比如200、401等等;第二个参数是信息头,包括一个项目为(header_name, header_value)的列表;第三个参数exc_info 用来在出错的时候传递信息。

start_response的返回值是另一个callable:write(body_data),用来写入内容体数据。但是这个callable是为了兼容老的程序,新程序不应使用。推荐的做法是通过之前a/f提供的callable来返回一个iterable,通过遍历这个iterable来获取需要发送的字节流。s/g侧不需要缓存字节流,a/f侧可以根据自己的需要来缓存字节流。

如果这个iterable有__len__()方法,那么必须每次调用都返回相同的结果,也就是需要发送的字节流的段数。如果这个iterable有close()方法,那么s/g侧必须在处理完request后调用这个close()方法。

s/g侧有可能不会完全消耗iterable的内容。另外iterable在发送第一段内容的时候,必须保证start_repsonse已被调用。

其他

(本篇完)