Minimal WSGI App In Python

UPDATE@201801: 很早的两篇文章,从 Python 文档里面摘取出来放到一起,这样可以有个整体认识。另外现在使用native wsgi API来编写wsgi app似乎也不太多了,大多数情况都是使用比较成熟的wsgi framework来写,比如flask, django. 文章里面使用uwsgi来启动wsgi app, 也可以考虑 gunicorn

WSGI(web server gateway interface)定义了一个web server的标准编程接口。开发着只需要按照这个接口来实现应用,然后将模块运行在标准化的container上,就实现了一个web server.

def logic(environ,start_response):
    start_response('200 OK', # status code
                   [('Content-type','text/plain')]) # header
    return ("OK",)

对于logic需要处理两个参数:

之后我们只需要选择一个合适的框架或者容器就可以运行起来了。python内置了一个WSGI framework。这里的validator可以帮助外围做一些验证。

def run():
    vlogic=validator(logic)
    httpd = make_server('', 8000, vlogic)
    httpd.serve_forever()

内置framework使用的是单进程启动模式,我们也可以修改成为多进程模式。更好的方式是利用已有的webserver framework比如gunicorn。假设上面的文件为x.py, 那么使用下面方式启动即可

[dirlt@compaq-pc] > gunicorn -w 4 x:logic
2012-08-30 23:18:59 [16116] [INFO] Starting gunicorn 0.13.4
2012-08-30 23:18:59 [16116] [INFO] Listening at: http://127.0.0.1:8000 (16116)
2012-08-30 23:18:59 [16116] [INFO] Using worker: sync
2012-08-30 23:18:59 [16119] [INFO] Booting worker with pid: 16119
2012-08-30 23:18:59 [16120] [INFO] Booting worker with pid: 16120
2012-08-30 23:18:59 [16122] [INFO] Booting worker with pid: 16122
2012-08-30 23:18:59 [16121] [INFO] Booting worker with pid: 16121
^C2012-08-30 23:19:09 [16120] [INFO] Worker exiting (pid: 16120)
2012-08-30 23:19:09 [16116] [INFO] Handling signal: int
2012-08-30 23:19:09 [16119] [INFO] Worker exiting (pid: 16119)
2012-08-30 23:19:09 [16122] [INFO] Worker exiting (pid: 16122)
2012-08-30 23:19:09 [16121] [INFO] Worker exiting (pid: 16121)
2012-08-30 23:19:09 [16116] [INFO] Shutting down: Master

如果上面WSGI程序修改成为下面的话,那么在访问web页面的时候会出现如下错误 "Error code: ERR_INCOMPLETE_CHUNKED_ENCODING".

def run(environ,start_response):
    start_response('200 OK', # status code
                   [('Content-type','text/plain')]) # header
    s = "OK".decode('utf-8')
    return (s,)

当时这个错误是以非常诡异的方式呈现的,而不是像我示例代码一样,当时s是从sqlite3读取的类型为TEXT的某个字段。WSGI要求返回对象必须是str类型而不能是unicode类型。


python运行web大约有下面三种方式:

各自优缺点分别是:

因为自己搭建fantuan.dirlt.com使用到了子域名,所以最终使用方案3(nginx + uwsgi + web.py). 配置步骤如下:

在nginx/site-enables里面从default产生一份新的配置文件,修改内容

server {
        server_name fantuan.dirlt.com;
        location / {
                include uwsgi_params;
                uwsgi_pass  127.0.0.1:8001;
        }
}

也就是说对于fantuan.dirlt.com这个请求包含uwsgi_params里面的参数全部转发到127.0.0.1:8001这个端口。

然后在本地启动uwsgi绑定在127.0.0.1:8001这个端口上面。uwsgi支持配置文件:

[uwsgi]
chdir = .
module = server:application
master = True
processes = 4
socket = 127.0.0.1:8001
vacuum = True
max-requests = 128