博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python WSGI
阅读量:7068 次
发布时间:2019-06-28

本文共 5130 字,大约阅读时间需要 17 分钟。

Python中的WSGI

简单来看,wsgi是web组件的接口规范,在wsgi规范里,wsgi把web组件分成三个部分,wsgi server,wsgi middleware,wsgi application

application

更多的时候,我们关心的只是wsgi application, wsgi application就是一个Python中的callable对象(函数,或定义了__call__方法的类等), 接受两个参数,environ和start_response,参数只是一个名字而已,environ指的是环境变量,start_response是一个回调函数。在实际创建一个运行的app时,一个参数都不需要我们传,无论是environ还是回调函数都由服务器,也就是wsgi server负责。

environ

environ 包括 服务器环境变量,客户端环境变量,和请求中的数据method,path等等。environ是怎么生成的呢?

wsgi server主要分为两部分,server和handler。server监听端口,handler处理请求。server接受到一个request,解析客户端environ,bind一个handler,handler解析请求,将请求信息放入environ,最后服务器端环境变量也放入environ中。这就是environ的全部了。

start_response

在wsgiref中,回调函数start_response的源码是下面这样的:

def start_response(self, status, headers,exc_info=None):

"""'start_response()' callable as specified by PEP 333"""    if exc_info:        try:            if self.headers_sent:                # Re-raise original exception if headers sent                raise exc_info[0], exc_info[1], exc_info[2]        finally:            exc_info = None        # avoid dangling circular ref    elif self.headers is not None:        raise AssertionError("Headers already set!")    assert type(status) is StringType,"Status must be a string"    assert len(status)>=4,"Status must be at least 4 characters"    assert int(status[:3]),"Status message must begin w/3-digit code"    assert status[3]==" ", "Status message must have a space after code"    if __debug__:        for name,val in headers:            assert type(name) is StringType,"Header names must be strings"            assert type(val) is StringType,"Header values must be strings"            assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"    self.status = status    self.headers = self.headers_class(headers)    return self.write

函数接受两个参数,status,也就是HTTP状态码,和headers,请求头。函数验证这两个信息,并将其塞入服务器。最后调用write方法,write方法的功能是“to buffer data for send to client”,也就是把信息再塞回客户端。

说到这,我们就可以看看一个在PEP3333中给出的简单的wsgi app了。

HELLO_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]

如上所述,两个参数,environ, start_response, 回调函数start_response传入status和headers,最后返回一个字符串,也就是服务器返回给客户端的核心数据。

同样,我们说过,一个wsgi application是一个callable对象,只要他是callable(实现__call__方法)的就可以。在PEP3333中也给出了一个简单的类形式的app:

class AppClass:

def __call__(self, environ, start_response):    status = '200 OK'    response_headers = [('Content-type', 'text/plain')]    start_response(status, response_headers)return [HELLO_WORLD]

到这,其实wsgi的结构很清晰了,最后,还差一个wsgi middleware。

middleware

按照PEP3333的说法,wsgi server是server端的东西,wsgi app是应用端的东西,并不是说middleware是中间的东西,middleware是一个两头兼顾的东西。

我们可以把app看成一个蛋糕,middleware则是这块蛋糕的包装。web服务中,例如session,route,auth等等,都是用middleware实现的。

例如一个PEP3333中的这个转换piglatin的wsgi middleware:

from piglatin import piglatin

class LatinIter:

"""Transform iterated output to piglatin, if it's okay to do soNote that the "okayness" can change until the application yieldsits first non-empty bytestring, so 'transform_ok' has to be a mutabletruth value."""def __init__(self, result, transform_ok):    if hasattr(result, 'close'):        self.close = result.close    self._next = iter(result).__next__    self.transform_ok = transform_okdef __iter__(self):    return selfdef __next__(self):    if self.transform_ok:        return piglatin(self._next())   # call must be byte-safe on Py3    else:        return self._next()

class Latinator:

# by default, don't transform outputtransform = Falsedef __init__(self, application):    self.application = applicationdef __call__(self, environ, start_response):    transform_ok = []    def start_latin(status, response_headers, exc_info=None):        # Reset ok flag, in case this is a repeat call        del transform_ok[:]        for name, value in response_headers:            if name.lower() == 'content-type' and value == 'text/plain':                transform_ok.append(True)                # Strip content-length if present, else it'll be wrong                response_headers = [(name, value)                    for name, value in response_headers                        if name.lower() != 'content-length'                ]                break        write = start_response(status, response_headers, exc_info)        if transform_ok:            def write_latin(data):                write(piglatin(data))   # call must be byte-safe on Py3            return write_latin        else:            return write    return LatinIter(self.application(environ, start_latin), transform_ok)

middleware与函数装饰器很像。

最后,一个应用的middleware不止一层,middleware可能像下面一样工作:

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

webframework

最后我们来看webframework,现在回想一下包括Django,Flask等框架,我们可以察觉出Python的web框架并不是特别的难以搭建。在4年前,第一个版本的Flask,只有短短600行代码,并且其中充斥着大量的注释(文档)。

一般来说,一个python的webframework需要一个wsgi工具集(werkzeug, webob(pylons)),一个模板渲染引擎(mako,jinja2)和一个ORM数据库工具集(sqlalchemy),还有其他的包括dispatcher,mail,json等支持,这样我们可以胶合一个自己的框架。

转载地址:http://nzell.baihongyu.com/

你可能感兴趣的文章
访问者模式
查看>>
Go routine调度
查看>>
Python 二分查找与 bisect 模块
查看>>
webpack4系列教程(十):总结
查看>>
【性能优化】quicklink:实现原理与给前端的启发
查看>>
剥开比原看代码16:比原是如何通过/list-transactions显示交易信息的?
查看>>
单行文字向上滚动
查看>>
vue进阶2-构建基础框架
查看>>
TiDB 源码阅读系列文章(十五)Sort Merge Join
查看>>
打造RecyclerView的n级列表
查看>>
正则匹配所有括号中的内容&PHP实现
查看>>
Vue & Bootstrap 结合学习笔记(二)
查看>>
深入理解flutter的编译原理与优化
查看>>
如何将FPGA资源平民化?阿里工程师有了新突破
查看>>
聊聊HystrixThreadPool
查看>>
Android NDK初识
查看>>
Node.js究竟是什么?
查看>>
阿里云E-HPC赋能制造业仿真云弹性
查看>>
Golang 微服务教程(一)
查看>>
web压力测试工具wrk安装及使用
查看>>