动态感觉 静观其变

居住地:江西南昌,msn:xlp223(at)hotmail.com,gmail talk:myhat123(at)gmail.com, 欢迎交流。喜欢python,也喜欢rails框架。

逝者如斯
网志分类
· 所有网志
· python学习
· pylons学习
· erlang学习
· ruby学习
· linux
· dotnet
· java
· 其他动态语言
· 感想心得
· ice学习
· 生活琐事
· 其他小玩意
搜索本站
友情链接
· 我们的小歪
· 管理我的Blog
· limodou的学习记录
· ywl51
· 花钱的年华
· python资料
· hd的blog
· oneZ
· hgf
· devin's braindump
· pylons
· sqlalchemy
· michael
· xyb
· kjd
· eiffelqiu
· okpython中国

订阅 RSS

0179108

歪酷博客


« 上一篇: Why so many Python web frameworks? 下一篇: 再看paste »
Hzg @ 2006-10-28 20:42

注:在wsgi.org上看到一篇文章,是网站推荐的文章,我看了一下,粗看没有什么,细细品味,品出了一些味道,对理解wsgi是一篇绝佳的文章,特别是对paste deploy的点拨,有点顿悟感觉。原文出自:http://isapi-wsgi.python-hosting.com/wiki/WSGI-Gateway-or-Glue

WSGI-Gateway or Glue?

Introduction

WSGI是由pje在寻找web server和python web app或framework之间简单而通用的接口的结果。原先是叫python web container interface。PEP333之前的讨论稿时2003.10.8张贴到python web sig中,经过了python社区很多方面的有效讨论和修改,它逐渐演变成Web Server Gateway Interface,并最终提交成PEP 333。
那么WSGI试图要解决什么问题呢?一个python程序员面对许多web framework可供选择的时候,或者是framework中部分组件的时候,运行framework的web server是一个决定性的因素.对于一个framework作者,为所有的web server创建适配器是不可能完成的任务,如果framework作者面向WSGI API来编程,那只要web server有WSGI适配器的话,framework用户就能选择他们自己需要的web server了.

How WSGI works

PEP文档写的很好,非常容易理解,它是关于WSGI 知识最好的资料,而我们这里只是WSGI的基本知识。

WSGI规范了2个接口,一个接口是为web server与app的交互,另一个接口是为app与web server的交互。

对于web server与app交互,它是调用一个函数或一个callable对象,这些由app提供。这个函数或对象有2个位置参数,environ和start_response,environ参数必须是一个内建的python字典类型,包含有CGI形式的环境变量,比如REQUEST_METHOD,必要的WSGI变量,也包括server扩展变量。start_response则是一个python函数。

对于app与web server的交互,app准备它要发送的header信息,然后调用给定的start_response,并带有startus状态码和一个header信息列表,然后app准备响应信息的body,形式是字符串列表或是字符串迭代器,返回的响应信息被传给web server。

在接收到来自app的列表或迭代器中含有的响应信息,web server会把字符串以流形式发送给client。

来点代码吧,考虑一下下面简单的CGI脚本:

#!/usr/bin/env python
print 'Content-type: text/plain\n\n'
print 'Hello world!'


作为一个WSGI app,我们这样来编码:
(hello_world.py)

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!\n']


或者面向对象的方式则是:

class WSGIAppClass:
    """Produce the same output, but using a class
    """

    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        self.start(status, response_headers)
        yield "Hello world!\n"

现在要测试我们的代码,我们配置wsgiref模块中的SimpleHTTPServer。

from wsgiref import simple_server
import hello_world

httpd = simple_server.WSGIServer(('',8000),simple_server.WSGIRequestHandler)
httpd.set_app(hello_world.application)
httpd.serve_forever()


然后我把它部署到使用FastCGI的apache上:

from flup.server.fcgi import WSGIServer
import hello_world

WSGIServer(hello_world.application).run()


或者部署到使用ISAPI的IIS上:

import isapi_wsgi
import hello_world
# The entry points for the ISAPI extension.
def __ExtensionFactory__():
    return isapi_wsgi.ISAPISimpleHandler(hello = hello_world.application)

if __name__=='__main__':
    # If run from the command-line, install ourselves.
    from isapi.install import *
    params = ISAPIParameters()
    # Setup the virtual directories - this is a list of directories our
    # extension uses - in this case only 1.
    # Each extension has a "script map" - this is the mapping of ISAPI
    # extensions.
    sm = [
        ScriptMapParams(Extension="*", Flags=0)
    ]
    vd = VirtualDirParameters(Name="isapi-wsgi-hello",
                            Description = "ISAPI-WSGI Hello WOrld",
                            ScriptMaps = sm,
                            ScriptMapUpdate = "replace"
                            )
    params.VirtualDirs = [vd]
    HandleCommandLine(params)

ISAPI上的部署有些例外,在其他的WSGI webserver适配器则是相当简单的脚本。

为了更好地理解一个webserver适配器是如何实现的,pep 333文档上描述的CGI适配器是最好的起点。

WSGI Web Server Implementations



WSGI Enabled Frameworks



WSGI Middleware

在过去的6个月里,WSGI的讨论和开发已经开始聚焦于WSGI Middleware上了,也就是使用python组件,这些组件是支持WSGI app和Server API的,把这些组件用pipeline管道线连接起来创建一个web app。下面是一个简单的WSGI Authentication组件,我们用它来包装一个已经存在的WSGI app外:

class AuthenticationMiddleware:
    def __init__(self, app, allowed_usernames):
        self.app = app
        self.allowed_usernames = allowed_usernames

    def __call__(self, environ, start_response):
        if environ.get('REMOTE_USER','anonymous') in self.allowed_usernames:
            return self.app(environ, start_response)
        start_response(
            '403 Forbidden', [('Content-type', 'text/html')])
        return ['You are forbidden to view this resource']


现在部署一下这个代码,就用PEP 333上的WSGI CGI适配器来运行它,

#!/usr/local/bin/python2.4
import hello_world
import middleware

allowed_users = ['guido','monty']

if __name__ == '__main__':
    from cgi_wsgi import run_with_cgi
    run_with_cgi(middleware.AuthenticationMiddleware(
        hello_world.application,allowed_users))

(注:我还是用wsgiref的Simple HTTP Server)
WSGIUtils,Python Paste,flup,Python Web Modules这些包都提供了middleware组件,有session management,error handling,authentication,compression和URL parsing。( 还有wsgi_xlst,pyfileserver,省略)

Configuration

在创建一个大规模的python web app中使用一些框架中立的组件时,会有一些麻烦和问题。组合所有的middleware组件的代码会显得很乱,看看这个假设的代码:

def configure(app):
    return ErrorHandlerMiddleware(
            SessionMiddleware(
             IdentificationMiddleware(
              AuthenticationMiddleware(
               UrlParserMiddleware(app))))))

if __name__ == '__main__':
    app = Application()
    app_pipeline = configure(app)
    server = Server(app_pipeline)
    server.serve()


一旦把需要传入的参数加入,代码的维护和调试将会变成噩梦。开发一个标准的方式来配置WSGI app已经成为Python Web SIG讨论的话题。Ian Bicking已经开发了Paste Deployment,这是一个用来查找和配置WSGI app和server的系统。要让Paste Deployment来配置加载WSGI app,需要用一个app factory来包装WSGI app。

(hello_world.py)

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!\n']

def app_factory(global_config, **local_config):
    return application

配置文件(config.ini)

[app:main]
paste.app_factory = hello_world:app_factory

相应的代码是:

from paste.deploy import loadapp
wsgi_app = loadapp('config:/path/to/config.ini')

(注:这是uri,一定要用绝对路径,如我的机子上是=>d:\work\wsgi\config.ini)

运行环境的部署的WSGI代码,我们用FastCGI:

from flup.server.fcgi import WSGIServer
WSGIServer(wsgi_app).run()

(注:我还是用wsgiref的simple_server)

Paste Deploy配置文件有一些标签来定义多个application,global,local变量,filter和定义的pipeline。这个pipeline的定义是用来简化带有WSGI middleware的app的创建。把我们前面写的Authentication Middleware加入一个filter,这个是由paste deploy使用,我们需要创建一个filter factory。

(filter_auth.py)

def auth_filter_factory(global_conf, **local_conf):
    if local_conf.has_key('allowed_users'):
        allowed_users = local_conf['allowed_users']
    def filter(app):
        return AuthenticationMiddleware(app, allowed_users)
    return filter

然后我们用一个配置文件pipeline把这个AuthenticationMiddleware和其他的filter串起来:

[pipeline:main]
pipeline = errorhandler session ident auth hello

[app:hello]
paste.app_factory = hello_wsgi:app_factory

[filter:auth]
paste.filter_factory = filter_auth:auth_filter_factory
allowed_users = ['guido', 'monty']

[filter:ident]
....

(注:这里的配置要根据自己的机子实际情况来调整)

如果我们向变换另一个authentication方法,配置文件只要更改为另一个authentication filter就行了。

更多的配置信息,可以看Paste Deployment文档。

Conclusions

WSGI是什么,一个gateway还是glue?我想这篇文章已经说明WSGI的两方面的特点。它既有webserver和python web app之间交互良好的API,也能把框架中立的组件glue粘合在一起。......


最新评论


beyking

2006-11-03 22:31 网址: http://china-django.com

原来django自带的WSGI.py就是照这个标准做啊


评论 / 个人网页 / 扔小纸条
* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 


 

分类小组论坛
杂谈 , 娱乐、八卦 , 文学、艺术 , 体育 , 旅游、同城 , 象牙塔 , 情感 , 时尚、生活 , 星座 , 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定