理解PEP333-WSGI
声明:这篇文章只是为了整体理解WSGI,会忽略很多细节,要详细了解请参看文后的参考资料

WSGI概述
WSGI全称是Python Web Server Gateway Interface(Python Web服务网关接口)仅针对名字可以做出一下总结:
- 1、Python Web Server Gateway Interface:这个规范是针对Python的
- 2、Python Web Server Gateway Interface:这个规范是针对Web服务相关的
- 3、Python Web Server Gateway Interface:这个规范是针对服务网关处的
- 4、Python Web Server Gateway Interface:这个规范是一种接口定义,不是具体实现
上面这样按照字面文本切分来理解也许是错的,但是在这里用来梳理理解我认为还是可以的。首先条目1、2、4应该是没问题,比较难理解的是3。3比较难理解是因为在我们的日常学习、开发的经历中,gateway/网关这一个词的准确指代是不明确、不固定的,这个词非常笼统与抽象,业务逻辑上集束处可以被成为网关,协议转换处可以被成为网关,权限分层处可以被称为网关……在基础的HTTP架构里,网关原本是用于称呼协议代理转换的那一部分,比如我们平常通过网页首发QQ邮件,浏览器后服务商后台进行通讯使用的是HTTP(S)协议,可e-mail常规协议是smtp、pop3这些,所以在中间一般经历了HTTP(S)到stmp等协议的转换,这一部分就是传统上基于HTTP服务架构中的网关。那么WSGI中的网关是什么意思呢?是不是协议转换?答案是否定的。在WSGI中所谓的网关是Web服务器与Web应用之间的衔接处,他使用的是类CGI之中网关的意思,就是Web服务器和动态Web程序之间的衔接。静态Web站点需要的软件程序只有Web服务器,Web服务器对文件系统进行相应的映射提供静态资源服务(HTML、图片等),但是动态网站需要处理业务逻辑的程序,业务逻辑程序通过不同的输出渲染输出不同的结果再由Web服务器传送给上游客户端。这样就产生了Web服务器和业务程序衔接的问题,就产生了cgi、fast-cgi。而WSGI是用来统一Web服务器和Python Web应用/框架之间接口的规范。
其实根据上面的描述可以看到业务逻辑程序概念上和网络传输没有关系,比如我们用Flask写的Web程序其实只是业务逻辑,真正处理HTTP网络传输的是Web服务器,只不过Flask为了便于开发自身携带了一个开发型Web服务器。
那WSGI有什么优势呢?为什么要有WSGI呢?首先要说明的是没有WSGI也是可以的,但是如果没有WSGI,每一个Web应用就要有单独的Web服务器,或者对某一个Web服务器做各种的兼容性的改动;有了WSGI规范,那么凡是支持该规范接口的Web服务器和Web应用就可以搭配使用提供服务。
WSGI规范主要骨架
刨去细节,从整体上看,WSGI对三方的规范:Web服务器规范、Web应用规范、中间件规范
Web服务器规范:
服务器必须提供两样东西: 一是environ环境字典,二是start_response可调用函数
其中:
- environ 字典必须包涵一定的数据项,类似于CGI environment
- environ包含的字段样例如下
- environ['wsgi.input'] = sys.stdin.buffer
- environ['wsgi.errors'] = sys.stderr
- environ['wsgi.version'] = (1, 0)
- environ['wsgi.url_scheme'] = 'https'
- ...
- start_response是接受两个参数的回调函数
- 参数status: 包涵标准的HTTP状态字符串 例如:200 OK
- 参数response_headers:标准HTTP响应头列表
服务器像下面这样将包含HTTP请求信息传递给Web应用/框架:
iterable = simple_app(environ, start_response)
for data in iterable:
pass
# send data to client
可以看出构建响应头、调用start_response并构建数据一可迭代的形式返回是应用/框架的责任,通过HTTP将响应头和数据传递给上游是Web服务器的责任。
Web应用/框架规范
Web应用/框架必须是可调用的,可以是类、函数或者对象, __init__参数、 __call__参数或者函数必须如上面调用的样子
- 一个environ对象
- 一个可调用的start_response
Web应用/框架必须在返回数据之前调用start_response
Web应用/框架应该以可迭代的形式返回数据,比如:列表
一个简单的WSGI应用的例子
def app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello world!\n']
中间件规范:
中间件组建必须同时遵守Web服务端和Web应用断的规范要求,并添加了一些轻微的限制
中间件应尽可能透明
下面是一个简单的将字符串全部转换成大写的中间件
class Upperware:
def __init__(self, app):
self.wrapped_app = app
def __call__(self, environ, start_response): # 这里遵循应用端规范
# 下面两个遵循服务端规范
for data in self.wrapped_app(environ, start_response):
yield data.upper()
一个完整的WSGI应用运行样例
# coding:utf-8
"""使用python内带的wsgiref简单服务器作Web服务器"""
from wsgiref.simple_server import make_server
from urlparse import parse_qs
def simple_app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello World']
class Upperware:
def __init__(self, app):
self.wrapped_app = app
def __call__(self, environ, start_response):
for data in self.wrapped_app(environ, start_response):
yield data.upper()
def main(environ, start_response):
print environ
params = parse_qs(environ.get('QUERY_STRING', ''))
if 'true' in params.get('mid', []):
app = Upperware(simple_app)
else:
app = simple_app
return app(environ, start_response)
if __name__ == "__main__":
srv = make_server('localhost', 9797, main)
srv.serve_forever()
#https://www.programcreek.com/python/example/65645/wsgiref.simple_server.WSGIServer
# httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
# server_address = (addr, port)
# httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=False)
# httpd.daemon_threads = True
# httpd.set_app(wsgi_handler)
# httpd.serve_forever()
如果以mid=true为参数的话访问(不限路径),就会使得中间件生效,返回文本全部大写,若不带该参数或该参数不为‘true’,中间件就不会生效。
再重复提一句:构建响应头、调用start_response并构建数据一可迭代的形式返回是应用/框架的责任(业务逻辑),通过HTTP将响应头和数据传递给上游是Web服务器的责任(网络传输)。,Web框架要处理的不是HTTP传输问题,是应用逻辑构建问题,比如说路由系统、上下文、模板渲染等等。还有就是现实世界也不是非此即彼,比如说Web服务器也可以直接构建路由系统,Web服务器和Web框架的编写是技术活,也是力气活(需要实现很多规范的细节)
声明:这篇文章只是为了简单整体理解WSGI我自己的一点浅薄之见,要详细了解请参看文后的参考资料
参考资料
- HTTP 权威指南
- HTTP MDN
- PEP333
- PEP3333
- Learn about WSGI
理解PEP333-WSGI的更多相关文章
- python Web开发你要理解的WSGI & uwsgi详解
原文:https://www.jb51.net/article/144852.htm WSGI协议 首先弄清下面几个概念: WSGI:全称是Web Server Gateway Interface,W ...
- 如何理解Nginx, WSGI, Flask(Django)之间的关系
如何理解Nginx, WSGI, Flask(Django)之间的关系 值得指出的是,WSGI 是一种协议,需要区分几个相近的名词: uwsgi 同 wsgi 一样也是一种协议,uWSGI服务器正是使 ...
- 如何理解Nginx, WSGI, Flask之间的关系
概览 之前对 Nginx,WSGI(或者 uWSGI,uwsgi),Flask(或者 Django),这几者的关系一存存在疑惑.通过查阅了些资料,总算把它们的关系理清了. 总括来说,客户端从发送一个 ...
- 浅析uWSGI、uwsgi、wsgi
WSGI协议 首先弄清下面几个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web ...
- wsgi&nginx-理解
WSGI协议 首先弄清下面几个概念:WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web ...
- wsgi & cgi的一些概念解释
可以看这里 https://www.zhihu.com/question/19998865 如何理解 CGI, WSGI?修改 写补充说明 举报 添加评论 分享 • 邀请回答 默认排序 按时间排序 1 ...
- CGI,WSGI区别
WSGI 参考link:https://jingtyu.gitbooks.io/learning-openstack/content/351-usgi.html(本人的gitbook) 个人理解: w ...
- 网关协议:CGI和WSGI
通常服务器程序分为web服务器和应用程序服务器.web服务器是用于处理HTML文件,让客户可以通过浏览器进行访问,主流的web服务器有Apache.IIS.Nginx.lighthttpd等.应用服务 ...
- wsgi和asgi的关系
什么是WSGI #CGI CGI(Common Gateway Interface,通用网关接口),定义客户端与Web服务器的交流方式的一个程序,例如正常情况下客户端发送过来一个请求,根据HTTP协议 ...
- 2020年是时候更新你的技术武器库了:Asgi vs Wsgi(FastAPI vs Flask)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_167 也许这一篇的标题有那么一点不厚道,因为Asgi(Asynchronous Server Gateway Interface) ...
随机推荐
- 面试题:编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。(c++实现)
实例说明 示例 1: 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: 输入: ...
- ASP.NET 网站管理工具
ylbtech-Miscellaneos:ASP.NET 网站管理工具 1. 网站管理工具概述返回顶部 网站管理工具概述 介绍 使用网站管理工具,可以通过一个简单的 Web 界面来查看和管理网站配置. ...
- 斯坦福CS231n学习--初识
课程主页:CS231n: Convolutional Neural Networks for Visual Recognition 关注其:Course Project主页 视频学习:云课堂 斯坦福C ...
- CentOS7下FTP的安装与配置
1.安装vsftpd 1 [root@localhost modules]# yum install -y vsftpd 2.编辑ftp配置文件 1 [root@localhost modules]# ...
- linux下安装python dlib依赖
dlib是主要用于机器学习的库,封装了机器学习算法,可以非常方便的实现比如人脸识别,车辆识别,物体检测以其他很多功能,dlib默认使用C++进行开发,另外图像识别有一部分支持python接口开发,上手 ...
- python3用BeautifulSoup用re.compile来匹配需要抓取的href地址
# -*- coding:utf-8 -*- #python 2.7 #XiaoDeng #http://tieba.baidu.com/p/2460150866 #标签操作 from bs4 imp ...
- 修改和查询sqlserver里面的xml 好像只能一个个改不能批量
select [ExtendFieldId], [Setting].value('(/UploadFileViewModel/UploadProviderKey)[1]', 'nvarchar(max ...
- 可显示行号的log工具
import android.util.Log; /** * (ExtendedLog=>ELog)可以记录行号,类名,方法名的Log工具 * * @author Fantouch */ pub ...
- 6.翻译系列:EF 6 Code-First中数据库初始化策略(EF 6 Code-First系列)
原文链接:http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-firs ...
- 【6集iCore3_ADP触摸屏驱动讲解视频】6-5 底层驱动之SDRAM读写(下)
源视频包下载地址: 链接:http://pan.baidu.com/s/1jIC2LKy 密码:zyn3 银杏科技优酷视频发布区: http://i.youku.com/gingko8