首先理解下面三个概念:
WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。
uwsgi:与WSGI一样是一种协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。
uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。
WSGI协议主要包括server和application两部分:
其中application部分:
示例代码:
def application(environ, start_response): status = '200 OK' response_headers = [('Content-Type', 'text/html')] # application内部调用start_response start_response(status, response_headers) # 解析environ信息,业务逻辑处理后,返回对应的响应信息(下面代码只是模拟业务处理) file_name = environ['PATH_INFO'] if file_name == "/index.py": return index(file_name) elif file_name == "/center.py": return center(file_name) else: return 'Hello world a simple WSGI application!'
有了WSGI,我们在框架中只关心如何从environ这个dict(wgsi规定传过来一个字典)对象拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。
整个application()函数本身没有涉及到任何解析HTTP的部分。 也就是说,底层代码不需要我们自己编写,我们只负责业务逻辑部分即可。
但是我们想一下,这个application()函数怎么调用?如果我们自己调用,两个参数environ和start_response我们没法提供,返回的str也没法发给浏览器。
截取server端部分代码实例如下:
# 重点关注逻辑 # 准备一个字典,里面存放需要传递给web框架的数据 env = dict() # ----------更新--------- env['PATH_INFO'] = file_name # 例如 index.py(模拟请求信息) # 重点关注逻辑 # 服务器调用框架中实现的application函数,并将包含请求信息的字典和获取响应头的函数传入 response_body = self.application(env, self.start_response) # 合并header和body(响应客户端的请求,这个逻辑不用关注) response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0]) response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % len(response_body.encode("utf-8")) for temp_head in self.headers[1]: response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n" response += response_body client_socket.send(response.encode('utf-8')) # 重点关注逻辑 # server端实现了start_response函数的定义 def start_response(self, status, headers): """这个方法,会在 web框架中被默认调用""" response_header_default = [ ("Data", time.time()), ("Server", "ItCast-python mini web server") ] # 将状态码/相应头信息存储起来 # [字符串, [xxxxx, xxx2]] self.headers = [status, response_header_default + headers]
这段代码,是在客户端请求动态资源时启动,即服务器需要向后端框架请求资源。代码解析已在代码中注释。
所以我们基本可以获得如下结论:
要实现WSGI协议,必须同时实现web server端和web application端
当前运行在WSGI协议之上的web框架有Torando,Flask,Django等
比较常用的WSGI协议服务器有:uWSGI,gunicorn等
1、框架需要实现WSGI协议,例如:Flask,Django等
2、environ 和 start_response 由 http server 提供并实现
3、environ 变量是包含了请求信息的字典
4、Application 内部在返回前调用 start_response
5、application()函数必须由WSGI服务器来调用
server要履行的任务:
1、接收HTTP请求
2、解析HTTP请求
3、准备 environ请求参数
4、定义 start_response 函数
5、组装响应头和相应体返回给客户端
application要履行的责任:
1、解析服务器发来的请求信息
2、根据请求信息,进行业务处理
3、返回所需要的数据
至此,您应该对WSGI有了一定的了解吧。
扩展阅读:
目前一些主要的实现了WSGI协议的服务器:
gunicorn
Gunicorn(从Ruby下面的Unicorn发展而来):依赖Nginx的代理行为,同Nginx进行功能上的分离。由于不需要直接处理用户来的请求(都被Nginx先处理),Gunicorn不需要完成相关的功能,其内部逻辑非常简单:接受从Nginx来的动态请求,处理完之后返回给Nginx,由后者返回给用户。
由于功能定位很明确,Gunicorn得以用纯Python开发:大大缩短了开发时间的同时,性能上也不会很掉链子。同时,它也可以配合Nginx的代理之外的别的Proxy模块工作,其配置也相应比较简单。
配置上的简单,大概是它流行的最大的原因。
uWSGI
因为使用C语言开发,会和底层接触的更好,配置也是比较方便,目前和gunicorn两个算是部署时的唯二之选。
以下是通常的配置文件
fcgi
不多说,用的少。
bjoern