首页 > 代码库 > Python WSGI

Python WSGI

因为服务都以restful api的方式提供给外界访问,于是又要看WSGI,要用到PasteDeploy库,但是感觉资料有些难懂尤其是paste.ini的使用上,下面几篇还算不错

[1] http://wanglianghuaihua.blog.163.com/blog/static/5425153120138273471531/

[2] http://pythonpaste.org/deploy/ ([1]是对[2]的翻译,不过有些部分没有在[1]中出现,看看原文还是有必要的)

[3] http://smartzxy.iteye.com/blog/734050 (给了一个实例和一些分析)

WSGI的概念不想多扯,在我看来和CGI差不多,和ASP,PHP,serverlet总是那么相似,下面来看一个实例,超简单的一个http动态服务程序

#! /usr/bin/env pythonfrom wsgiref.simple_server import make_serverimport datetimedef default_wsgi_app(environ, start_response):	print ‘environment varibles:‘	for (k, v) in environ.items():		print "%15s : %s" % (k, v)		status  = ‘200 OK‘	headers = [(‘Content-type‘, ‘text/plain‘)]	start_response(status, headers)		return [‘HaHa HeHe...generated@‘,str(datetime.datetime.now())]httpd = make_server(‘‘, 8082, default_wsgi_app)httpd.serve_forever()

其中的default_wsgi_app就是一个请求处理过程,把这个函数给make_server创建一个wsgi server(这里是httpd变量),它就会把监听到的请求扔给default_wsgi_app这个函数处理。函数的签名就是WSGI的标准,environ用于表示环境(含有GET/POST参数)变量是一个dict, start_response的使用如上述代码所示,用来输出响应头(HTTP Response Header)(当然可能更复杂,还没看过源码),响应头输出后,就要开始输出响应体(HTTP Response Body),即响应内容。default_wsgi_app函数通过返回一个字符串list来作为请求的响应内容。然后wsgi server接收到default_wsgi_app函数返回内容后,就开始将数据发送到请求端,这样一次请求-响应过程结束了。

如果我们把这个default_wsgi_app改的复杂一些,加入session保持(通过在http header中设置cookie和服务端的全局变量中创建一个映射),url dispatcher就跟其他的如serverlet非常像了。

下面开始介绍PasteDeploy,它可以通过定义一个配置文件(ini格式,非常简单的键值赋值)把各个类似default_wsgi_app的WSGI响应处理函数组织起来(给他们不同的url路径映射),或者在其外围包裹一层filter对请求或者响应的内容做些预/后处理,这跟python的函数装饰器很像。但是我们不能掉进java的坑里面,什么AOP啊一大堆,简单实用又不失结构性的风格是派森大法最有魅力的地方。由于paste的配置文件非常灵活,还是从最简单的开始说起。

我们创建一个叫做demo-paste.ini的文件,内容如下:

[DEFAULT]server_name = WSGI DEMO SERVER[app:main]app_developer = hgfeaonapp_version = 1.0paste.app_factory = sample:custom_app_factory

先解释一下,

  • 在[DEFAULT]节中的变量定义都作为全局变量(如server_name)
  • [app:main]表示一个名称为main的WSGI实例的配置,在这里定义的变量作为专门用于这个实例的局部变量(如app_developer, app_version)
  • paste.app_factory = sample:custom_app_factory,表示WSGI的处理函数(如上例中的default_wsgi_app)由谁来生成,这里我们定义由sample模块中的custom_app_factory函数来生成

 其中paste.app_factory是Paste模块的一个参数它指向一个用于创建WSGI处理函数的函数,这个factory函数应该是如下形式:

paste.app_factory

The application is the most common. You define one like:

def app_factory(global_config, **local_conf):    return wsgi_app

The global_config is a dictionary, and local configuration is passed as keyword arguments. The function returns a WSGI application.

这个函数有两个入参一个是global_config,是一个dict,内容就是在paste.ini文件中[DEFAULT]一节中定义的变量,而另外一个kwargs型参数local_config也可以看成是一个dict,存储的是每个节中的局部变量。根据这些变量可以定义一个工厂(之所以这样叫是因为用到了工厂模式)函数,来返回不同的WSGI响应函数,或者说对响应函数对象做一些配置。下面给出这个工厂函数:

#! /usr/bin/env pythonimport datetimedef default_wsgi_app(environ, start_response):	print ‘environment varibles:‘	for (k, v) in environ.items():		print "%15s : %s" % (k, v)		status  = ‘200 OK‘	headers = [(‘Content-type‘, ‘text/plain‘)]	start_response(status, headers)		return [‘HaHa HeHe...generated@‘,str(datetime.datetime.now())]def custom_app_factory(global_config, **local_config):	# print the global variables defined in section [DEFAULT] section	print ‘Global Config:‘	for (k, v) in global_config.items():		print "%15s : %s" % (k, v)	# print the local variables defined in this non-DEFAULT section	# where the custom_app_factory is refered as 	# paste.app_factory = sample:custom_app_factory	print ‘Local Config:‘	for (k, v) in local_config.items():		print "%15s : %s" % (k, v)		return default_wsgi_app