Hello, WSGI

最新的工做中,有一部分HTTP API的任务,因而开始折腾Python WSGI...python

WSGI

先恶补理论吧,关于Python WSGI有2篇PEP须要看,PEP 0333PEP 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

  • the "server" or "gateway" side(下文称为“server端”)
  • the "application" or "framework" side(下文称为“application端”,framework本质上也是一种应用)

“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

Quick Start

好了,终于能够动手实践了,早已按耐不住啦!咱们先把上面的“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”页面输出,大功告成!

Learn More

本文的“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;

这些方面的知识,也许会有后续的文章作介绍;

相关文章
相关标签/搜索