最新的工做中,有一部分HTTP API的任务,因而开始折腾Python WSGI...python
先恶补理论吧,关于Python WSGI有2篇PEP须要看,PEP 0333和PEP 3333,前者是2003年的提案,后者在2010年对前者作了小幅修订,提案状态也已是“Final”,因此已经不是“提案”,已是协议规范了;flask
WSGI,是“Python Web Server Gateway Interface”的缩写,解决的是各类Web Server(好比Apache、Nginx)与各类Python Web框架(好比Flask、Tornado)之间互联互通的兼容性问题;vim
如PEP中描述,在没有一个统一协议规范之前,某个Python应用(Web框架、或者应用程序),可能仅支持运行在某一个Web Server下,应用开发者选择某个Web框架的同时,也就绑死了某个Web Server;另外,在某个Web框架写的应用代码,迁移到另一个Web框架,不必定能跑起来;因此,为了能让用户自由选择、组合使用任意的Web框架和Web Server,该PEP规范了必要的交互方式和数据结构;浏览器
注意,WSGI不是一个软件工具,它是一种协议规范的描述,它规范了“交互方式和数据结构”,任何Web Server、Gateway和Framework、Application,只要听从这个规范去实现,就必定能互联互通;既然是“交互”,就必定至少包含两方吧,PEP指出:bash
“application端”,必须提供一个“可调用的对象”供“server端”调用,“可调用的对象”通常是个入口函数,应用对HTTP请求的处理,要在这个入口函数内完成,函数最终返回HTTP Respone,好比生成的HTML;数据结构
下面的示例摘自PEP 3333:架构
pythonHELLO_WORLD = b"Hello world!\n" def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD]
“server端”,通常就是Web Server啦,最主要的任务就是接受到HTTP请求后,调用“application端提供的入口函数(好比上面的“simple_app”),另外应用程序里可能须要不少HTTP请求的信息(好比HTTP Method,GET/POST),这些信息,如何获取呢?须要“server端”在调用应用入口函数的时候做为函数参数传递,就是上面的“environ”,关于“environ”这个数据结构的规范,PEP中也是有详细描述的;app
关于“server端”实现的实例代码,稍稍复杂一点,搬运到这里,也不见得帮助理解,自行到PEP 3333查阅吧;框架
关于Python WSGI的理论介绍,最核心的都在这儿了,更细节的协议介绍,自行查阅吧;python2.7
好了,终于能够动手实践了,早已按耐不住啦!咱们先把上面的“simple_app”跑起来吧;
bash$ touch simple_app.py $ vim simple_app.py HELLO_WORLD = b"Hello world!\n" def application(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD]
好了,“application端”已经好了,那“server端”呢?咱们须要搞来一个实现了Python WSGI的Web Server,这里,我选择了,uWSGI,不要被它的名字迷惑,它实际上是一个功能很是全、实现了各类协议、支持各类的语言的“a full stack for building hosting services”,由于最先支持Python,因此取了这样一个名字,官方都说,名字已经支撑不起它的野心,哈哈;
本实践中,咱们要基于Python安装uWSGI:
bash$ pip install uwsgi
根据你的Python安装路径,uWSGI的二进制程序安装路径也会不一样,比我电脑上:
bash$ ls /usr/local/python2.7/bin/uwsgi
如今,“application端”和“server端”,都已经准备就绪了,咱们能够启动的这个简单的WSGI应用了:
bashuwsgi --http :9090 --wsgi-file simple_app.py
uWSGI会到simple_app.py文件中,找一个固定名字“application”的入口函数,当uWSGI收到HTTP请求时,就会调用该入口函数;
你在浏览器请求http://127.0.0.1:9090,应该会看到uWSGI的输出:
bash$ uwsgi --http :9090 --wsgi-file simple_app.py [pid: 1492|app: 0|req: 1/1] 127.0.0.1 () {34 vars in 626 bytes} [Sat Jun 20 15:32:14 2015] GET / => generated 11 bytes in 0 msecs (HTTP/1.1 200) 1 headers in 44 bytes (1 switches on core 0) [pid: 1492|app: 0|req: 2/2] 127.0.0.1 () {36 vars in 615 bytes} [Sat Jun 20 15:32:14 2015] GET /favicon.ico => generated 11 bytes in 0 msecs (HTTP/1.1 200) 1 headers in 44 bytes (1 switches on core 0)
此时,你的浏览器应该也已经有“Hello World”页面输出,大功告成!
本文的“Hello World”示例,仅仅是展现Python WSGI的框架结构,“server端”提供的HTTP请求信息“environ”彻底没有使用,无脑返回一个不变的字符串;
真正的应用,是须要根据功能要求,定制、填充那个application的入口函数的,应用开发者,能够本身代码实现,也能够依托于一些流行的WSGI框架和Python模块,好比:Flask框架、werkzeug
“server端”就没有什么发挥的空间了,选择一个支持WSGI协议的就行了,就像本文尝试的uWSGI,除非你想本身实现个Web Server;Nginx虽然不直接支持WSGI,但它支持uWSGI,这样把Nginx挡在uWSGI前面,uWSGI就能够专门处理动态的WSGI请求了,造成的架构,很是相似于PHP场景下的Nginx+PHP-FPM;
这些方面的知识,也许会有后续的文章作介绍;