认识WSGI

来源:互联网 发布:数据库黑客大曝光 编辑:程序博客网 时间:2024/06/03 20:22
WSGI是Web Server Gateway Interface的缩写。它是Python专有的一种接口规范(其它语言也有类似的规范,只是名字不一样而已,Python则是第一个提出该规范的语言)。该规范规定了WEB服务器与WEB应用框架之间的通信方式。

首先,WEB应用需要提供一个可调用的接口(如:函数);该接口接收2个参数:
  • 第一个参数是当前请求所有请求信息的字典对象
  • 第二个参数是一个回调函数


其次,WEB服务器需要定义一个回调函数,该回调函数接收2个参数:

  • 第一个参数是响应码
  • 第二个参数是响应头的列表


WSGI的通信流程如下:
  1. WEB服务器在接收到用户请求
  2. 组装本次请求的所有信息并存放在字典对象
  3. 调用WEB应用提供的接口,并传递响应的参数
  4. 从WEB应用接口获取返回的响应体内容
  5. 从传递的回调函数中获取响应码和响应头


总的来讲基本就是WEB服务器会把请求相关信息,通过调用接口的方式传递给WEB应用程序;接口WEB应用程序通过调用回调函数和返回值的方式,分别返回响应头和响应体内容给WEB服务器。其流程示意如下:



下面清单中是最简单的WSGI服务

#!/usr/bin/env python#coding:utf-8import socketfrom app import appg_status_code = g_rep_headers = Nonedef parse_headers(buf):headers = {}lines = buf.split('\r\n')for line in lines[1:]:line = line.strip()if not line:breaksp = line.split(':', 2)headers[sp[0]] = sp[1]return headersdef callback(status_code, rep_headers):global g_status_code, g_rep_headersg_status_code = status_codeg_rep_headers = rep_headersdef handle_request(client):global g_status_code, g_rep_headers    buf = client.recv(1024)headers = parse_headers(buf)rsp = app(headers, callback)headers = [":".join(header) for header in g_rep_headers]    client.send("%s\r\n%s\r\n\r\n" % (g_status_code, '\r\n'.join(headers)))    client.send(rsp)  def main():    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    sock.bind(('localhost',8080))    sock.listen(5)      while True:        connection, address = sock.accept()        handle_request(connection)        connection.close()  if __name__ == '__main__':  main()
该清单中实现了一个socket服务,它监控了本地的8080端口,当有用户请求到达时则会在handle_request函数中,通过WSGI的方式调用外部的app接口,该接口会直接返回响应内容,并且会执行传递给它的call_back函数,最后handle_request函数中会把分散的信息组织起来,发送给访问用户。

其对应的app服务接口定义如下(保存为app.py文件):

#!/usr/bin/env python#coding:utf-8def app(environ, start_response):##do some this with different pathdata = b"Hello, World!\n"start_response("200 OK", [("Content-Type", "text/plain"),("Content-Length", str(len(data)))])return iter([data])
该清单中只定义了一个app函数,也就是上一个清单中被引入的app接口。在app函数中可以根据不同的头信息来决定如何处理请求,最终返回对应的响应信息。

到目前为止,WSGI规范的说明就结束了,接着就是如何使用该规范。在日常的项目中,我们不会自己去写WSGI服务,也不会自己写WSGI的接口。因为这些都是比较公用的模块或框架,自然就有人已经写好了这些功能,我们只要直接使用即可。

首先,Python官方就自带了一个WSGI的服务,我们可以直接使用。方式如下:

#!/usr/bin/env python#coding:utf-8from wsgiref.simple_server import make_server from app import app httpd = make_server('localhost', 8080, app)  httpd.serve_forever()
该代码的功能与清单1基本相同,而我们只需要实现一个清单2中WSGI接口即可。

此外,还有很多的第三方WSGI库,比较流行的一个是gunicorn。官方给出的使用例子如下:

pip install gunicorn      ##安装gunicorn库gunicorn -w 4 app:app     ##启动WSGI服务,并指定app接口所在位置,这里是app.py文件下的app函数,需要确保在app.py所在目录执行
是不是有点惊为天人,我们尽然一行代码都不需要多写就可以把现有的WSGI接口集成到WSGI服务中。并且-w 4是指启动4个worker进程来提供服务,也就是说我们的WSGI接口通过gunicorn启动之后,除了更方便之外,还同时支持了多进程的并发能力。

既然WSGI有第三方这么好的实现,那么WSGI接口呢?答案是当然有的。并且目前Python的大部分WEB框架都是支持WSGI接口的,比如:Django、Flask、Tornado等。所以当我们需要使用WSGI服务的时候,其实就是配置好这些模块并相应的启动即可。下面是以Flask为例启动的WSGI服务的样例:

#!/usr/bin/env python#coding:utf-8from flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()
把上述清单保存到flask_demo.py中,然后在该文件所在目录执行如下命令:

gunicorn -w 2 flask_demo:app
该命令启动了2个gunicorn的worker来执行flask的app应用。