认识WSGI

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-8
import socket
from app import app

g_status_code = g_rep_headers = None

def parse_headers(buf):
	headers = {}
	lines = buf.split('\r\n')
	
	for line in lines[1:]:
		line = line.strip()
		
		if not line:
			break
		
		sp = line.split(':', 2)
		headers[sp[0]] = sp[1]
		
	return headers

def callback(status_code, rep_headers):
	global g_status_code, g_rep_headers
	
	g_status_code = status_code
	g_rep_headers = rep_headers

def 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-8

def app(environ, start_response):
	##do some this with different path
	data = 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-8
from 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-8
from flask import Flask
app = 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应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上帝De助手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值