flask的WSGI实现

? ? ? ? WSGI是python下,web应用(application/framework)与服务层(server/gateway)交互的一套协议。假设有框架A和框架B,二者和web server(比如apache)采用了不同的协议,那么为了使二者都能够在apache上正常运行,我们就需要写两个不同的模块供apache调用。python下的框架百花齐放,为每一个框架写一套模块明显不切实际。WSGI的出现使开发者只需要关注于应用层面而不用去考虑这些底层细节,减少了不必要的工作。?

WSGI简介1.application/framework

? ? ? ? 以下是两个典型application的实现方法,包括函数实现以及类实现

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!\n']class AppClass:    """Produce the same output, but using a class    (Note: 'AppClass' is the "application" here, so calling it    returns an instance of 'AppClass', which is then the iterable    return value of the "application callable" as required by    the spec.    If we wanted to use *instances* of 'AppClass' as application    objects instead, we would have to implement a '__call__'    method, which would be invoked to execute the application,    and we would need to create an instance for use by the    server or gateway.    """    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"
application必须返回一个迭代器。

返回迭代器而不是字符串的意义在于,字符串需要在内存中有一份完整的拷贝,迭代器按需生成结果,减少内存占用并且可以一边生成一边写入传输层,减少了时间的占用。

?

2.server/gateway

server负责处理接受socket请求,调用application以及响应请求。

application必须可以接受两个参数。

server接受请求后,立即调用application(environ, start_response)。两个参数,前者表示请求相关的环境变量,比如WSGI版本,请求的消息体等;后者为一个方法,这个方法在server处定义。start_response这个方法有着许多限制:

该函数必须接受两个参数以及一个可选参数(即?start_response(status, response_headers)).该函数的参数的类型以及值有着一些限制该函数在application中必须被调用,并返回一个用于写入HTTP响应体的write函数(即需要可以执行write(body_data))。server并不提供unicode支持,文本unicode的编解码在应用中实现。其它限制…

server端获得application的返回值之后,迭代将数据写入传输层。

Flask/werkzeug的WSGI实现1.端口监听以及响应

class BaseWSGIServer(HTTPServer, object):    """Simple single-threaded, single-process WSGI server."""    multithread = False    multiprocess = False    request_queue_size = 128    def __init__(self, host, port, app, handler=None,                 passthrough_errors=False, ssl_context=None):        if handler is None:            handler = WSGIRequestHandler        self.address_family = select_ip_version(host, port)        HTTPServer.__init__(self, (host, int(port)), handler)        self.app = app        self.passthrough_errors = passthrough_errors        self.shutdown_signal = False        if ssl_context is not None:            try:                from OpenSSL import tsafe            except ImportError:                raise TypeError('SSL is not available if the OpenSSL '                                'library is not installed.')            if isinstance(ssl_context, tuple):                ssl_context = load_ssl_context(*ssl_context)            if ssl_context == 'adhoc':                ssl_context = generate_adhoc_ssl_context()            self.socket = tsafe.Connection(ssl_context, self.socket)            self.ssl_context = ssl_context        else:            self.ssl_context = None

这是非常关键的一段代码。werkzeug创建WSGIserver的时候, __init__()函数有一个参数叫做handler。这个参数指明,在监听到请求之后使用哪一个类的实例去处理请求。在此处因为flask传递给werkzeug的handler值为None,所以werkzeug将会使用自己的一个WSGIResuestHandler类去处理请求(即WSGIResuestHandler.handle-> WSGIResuestHandler.handle _one_request-> WSGIResuestHandler.run_wsgi)。

2.应用层处理请求

WSGIResuestHandler.run_wsgi内部调用函数app(environ, start_response),应用层开始处理请求。对于flask而言,应用层的操作非常简单,一行代码就可以说明问题:

return self.view_functions[rule.endpoint](**req.view_args)

经过多层次的函数调用之后,最终application查找之前注册好的url rule对应的处理函数, 返回该函数处理之后的结果,也即一个iterable。每次的处理都会涉及到这些操作:

    def full_dispatch_request(self):        """Dispatches the request and on top of that performs request        pre and postprocessing as well as HTTP exception catching and        error handling.        .. versionadded:: 0.7        """        #第一次请求发生执行的操作        self.try_trigger_before_first_request_functions()        try:            #发送信号            request_started.send(self)            #请求发生前的操作            rv = self.preprocess_request()            if rv is None:                rv = self.dispatch_request()        except Exception as e:            rv = self.handle_user_exception(e)        #处理请求        response = self.make_response(rv)        #请求处理候的操作        response = self.process_response(response)        #全局信号        request_finished.send(self, response=response)        return response

至此,一个调用的大致流程就完成了。?

?

参考:

1.PEP 333?

2.捉摸Python的WSGI

3.AbtWebModules

flask的WSGI实现

相关文章:

你感兴趣的文章:

标签云: