Python语言 Web 应用:WSGI基础
小标 2018-11-06 来源 : 阅读 1041 评论 0

摘要:本文主要向大家介绍了Python语言 Web 应用:WSGI基础,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

本文主要向大家介绍了Python语言 Web 应用:WSGI基础,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

在Django,Flask,Bottle和其他一切Python
 web 框架底层的是Web Server Gateway Interface,简称WSGI。WSGI对Python来说就像 
Servlets对Java一样——一种用于web服务器并允许不同web服务器和应用框架基于通用API交互的通用规范。然而,对于大多数事情,Python版本实现相当简单。WSGI被定义在PEP 3333协议里面,如果在读完本文之后你想学到更多东西的话,作者建议读者先阅读一下简介。本文将从一个应用开发者的角度来向你介绍WSGI说明,并且向你展示怎样直接通过WSGI来开发应用程序(如果你迫不及待的话)。你的第一个WSGI应用下面是最基本的Python web应用:def app(environ, start_fn):
    start_fn('200 OK', [('Content-Type', 'text/plain')])    return ["Hello World!\n"]就是这样!整个文件。先命名为app.py然后在任何WSGI可编译服务器上面运行,然后你就可以得到一个Hello World并伴随一个200的响应状态码。你可以使用gunicorn来完成,通过pip(pip install gunicorn)来安装并执行gunicorn app:app。这条命令告诉gunicorn从应用模块里的应用变量去获取可调用的WSGI。刚才,十分兴奋吧。仅仅三行代码就可以运行一个应用?那一定是某种意义上的记录(不包括PHP,因为mod_php在起作用)。我敢打赌你现在一定想更加深入了解下去了。所以一个WSGI应用最重要的部分是什么呢?一个WSGI应用是Python可调用的,就像一个函数,一个类,或者一个有__call__方法的类实例可调用的应用程序必须接受两个参数:environ,一个包含必要数据的Python字典,start_fn,它自己是可调用的。应用程序必须能调用start_fn和两个参数:状态码(字符串),和一个头部以两个元组表述的列表。应用程序返回一个在返回体里包含bytes的方便的可迭代对象,流式的部分——例如,一个个只包含“Hello,World!”字符串的列表。(如果app是一个类的话,可以在__iter__方法里完成)例如下面两个例子和第一个是等价的:class app(object):

    def __init__(self, environ, start_fn):
        self.environ = environ
        self.start_fn = start_fn    def __iter__(self):
        self.start_fn('200 OK', [('Content-Type', 'text/plain')])        yield "Hello World!\n"class Application(object):
    def __call__(self, environ, start_fn):
        start_fn('200 OK', [('Content-Type', 'text/plain')])        yield "Hello World!\n"app = Application()你可能已经开始思考能用这些东西来做什么了,但是最可能相关的一项是用来写中间件。让它活跃起来中间件是一种方便扩展WSGI应用功能性的方法。因为你只需提供一个可调用的对象,你可以任意把它包裹在其他函数里。例如,假设我们想检测一下environ里面的内容。我们可以轻易地创建一个中间件来完成,如下所示:import pprintdef handler(environ, start_fn):
    start_fn('200 OK', [('Content-Type', 'text/plain')])    return ["Hello World!\n"]def log_environ(handler):
    def _inner(environ, start_fn):
        pprint.pprint(environ)        return handler(environ, start_fn)    return _inner

app = log_environ(handler)这里,log_environ是一个返回函数的函数,它在environ参数延迟原始回调之前装饰该参数。这样写中间件的优点是中间件和处理器不需要知道或者关心对方。你可以轻易地绑定log_environ到一个Flask应用上面,例如,因为Flask应用是WSGI应用。其他一些有用的中间件设计:import pprintdef handle_error(handler):
    def _inner(environ, start_fn):
        try:            return handler(environ, start_fn)        except Exception as e:            print e  # Log error
            start_fn('500 Server Error', [('Content-Type', 'text/plain')])            return ['500 Server Error']    return _innerdef wrap_query_params(handler):
    def _inner(environ, start_fn):
        qs = environ.get('QUERY_STRING')
        environ['QUERY_PARAMS'] = urlparse.parse_qs(qs)        return handler(environ, start_fn)    return _inner如果你不想让你的文件有一个很大的金字塔底的话,你可以使用reduce一次应用到多个中间件上。# Applied from bottom to top on the way in, then top to bottom on the way outMIDDLEWARES = [wrap_query_params,
               log_environ,
               handle_error]

app = reduce(lambda h, m: m(h), MIDDLEWARES, handler)利用start_fn参数的优点你也可以写装饰响应体的中间件。下面是一个内容类型头部是text/plain反转输出结果的中间件。def reverser(handler):

    # A reverse function
    rev = lambda it: it[::-1]    def _inner(environ, start_fn):
        do_reverse = []  # Must be a reference type such as a list

        # Override start_fn to check the content type and set a flag
        def start_reverser(status, headers):
            for name, value in headers:                if (name.lower() == 'content-type'
                        and value.lower() == 'text/plain'):
                    do_reverse.append(True)                    break

            # Remember to call `start_fn`
            start_fn(status, headers)

        response = handler(environ, start_reverser)        try:            if do_reverse:                return list(rev(map(rev, response)))            return response        finally:            if hasattr(response, 'close'):
                response.close()    return _inner由于start_fn和响应体的分离有一点混乱,但是还是完美运行的。同时请注意,为了严格遵循WSGI规范,如果存在的话,我们必须在响应体里检查close方法并且调用它。WSGI应用程序有可能返回一个write函数而不是一个调用处理器的可迭代对象,如果你想要你的中间件支持更早的应用的话,你可能需要处理这个问题。一旦你开始一点点把玩原生WSGI,你就开始理解为什么Python有一堆web框架。WSGI让从底层造一些东西变得十分简单。例如,你也许正在考虑下面的路由问题:routes = {    '/': home_handler,    '/about': about_handler,
}class Application(object):
    def __init__(self, routes):
        self.routes = routes    def not_found(self, environ, start_fn):
        start_fn('404 Not Found', [('Content-Type', 'text/plain')])        return ['404 Not Found']    def __call__(self, environ, start_fn):
        handler = self.routes.get(environ.get('PATH_INFO')) or self.not_found        return handler(environ, start_fn)如果你喜欢下面资源集合的灵活性的话,直接使用WSGI造轮子还是十分方便的。模板库:投入任何你喜欢的模板(例如,Jinja2,Pystashe)然后从你的处理器返回渲染后的模板!用一个库帮助你的路由,如Routes或者Werkzeug’s routing。实际上,如果你想轻松使用WSGI的话,看一看Werkzeug吧。使用任何Flask或者相似的数据库迁移库。当然,对于非专业的应用,你也可能想使用一下框架,那样的话,一些特殊的诸如此类的例子也可以得到合理解决。关于服务器呢?有许许多多服务WSGI应用的方法。我们已经讨论过Gunicorn了,一个相当好的选择。uWSGI是另外一个不错的选择。但是请确保在服务这些静态东西之前设置好nginx一类的东西,并且你应该有一个固定的开始节点。

本文由职坐标整理并发布,希望对同学们学习Python有所帮助,更多内容请关注职坐标编程语言Python频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程