Werkzeug 库以及 wrapper 模块



来源:fanchunke

fanchunke.me/Flask/Werkzeug库简介/



简介


Werkzeug是一个Python写成的WSGI工具集。它遵循WSGI规范,对服务器和Web应用之间的“中间层”进行了开发,衍生出一系列非常有用的Web服务底层模块。关于Werkzeug功能的最简单的一个例子如下:


from werkzeug.wrappers import Request, Response

def application(environ, start_response):

    request = Request(environ)

    response = Response("Hello %s!" % request.args.get('name', 'World!'))

    return response(environ, start_response)

if __name__ == '__main__':

    from werkzeug.serving import run_simple

    run_simple('localhost', 4000, application)


运行上面的例子,当在浏览器输入http://localhost:4000/就会向本地的服务器发出一个请求。在请求的过程中,werkzeug主要做了下面几件事情:


  1. 根据服务器和WSGI服务器产生的environ环境信息,封装一个Request实例,这个实例包含请求的所有信息;

  2. Web应用根据封装的Request实例信息,产生一个Response实例(上述例子只是输出一段字符串)。这个Response实例是一个可调用的WSGI应用;

  3. 上一步骤产生的可调用应用对象response调用response(environ, start_response)生成响应信息并发回客户端。调用函数是由WSGI规范规定的。


以上过程很好地将服务器和web应用分离开来:服务器不用考虑请求信息怎么被解析给web应用,以及后续怎么和web应用通信;web应用也不用考虑怎么将响应信息返回给服务器。服务器要做的只是提供web应用所需的请求信息,web应用提供的也只是响应信息,中间的处理过程werkzeug可以帮助完成。


wrappers模块


Werkzeug库中的wrappers模块主要对request和response进行封装。request包含了客户端发往服务器的所有请求信息,response包含了web应用返回给客户端的所有信息。wrappers模块对请求和响应的封装简化了客户端、服务器和web应用通信的流程。本文主要介绍wrappers模块中重要的类。


BaseRequest


BaseRequest是一个非常基础的请求类,它可以和其他的“混合”类结合在一起构建复杂的请求类。只要传递一个环境变量environ(由WSGI服务器根据请求产生),便可以构造一个BaseRequest实例。其构造函数如下:


def __init__(self, environ, populate_request=True, shallow=False):

    self.environ = environ

    if populate_request and not shallow:

        self.environ['werkzeug.request'] = self

    self.shallow = shallow


初始化后,形成的实例request便具有了一些属性可以访问,这些属性只能以“只读”的方式访问。例如:


  • url_charset

  • want_form_data_parsed

  • stream

  • args

  • data

  • form

  • values

  • files

  • cookies

  • headers

  • path

  • full_path

  • script_root

  • url

  • base_url

  • url_root

  • host_url

  • host

  • access_route

  • remote_addr


BaseRequest中还有两个类方法比较常用:


from_values(cls, *args, kwargs)**


@classmethod

def from_values(cls, *args, **kwargs):

    """Create a new request object based on the values provided.  If

    environ is given missing values are filled from there.  This method is

    useful for small scripts when you need to simulate a request from an URL.

    Do not use this method for unittesting, there is a full featured client

    object (:class:`Client`) that allows to create multipart requests,

    support for cookies etc.

    This accepts the same options as the

    :class:`~werkzeug.test.EnvironBuilder`.

    .. versionchanged:: 0.5

       This method now accepts the same arguments as

       :class:`~werkzeug.test.EnvironBuilder`.  Because of this the

       `environ` parameter is now called `environ_overrides`.

    :return: request object

    """

    from werkzeug.test import EnvironBuilder

    charset = kwargs.pop('charset', cls.charset)

    kwargs['charset'] = charset

    builder = EnvironBuilder(*args, **kwargs)

    try:

        return builder.get_request(cls)

    finally:

        builder.close()


这个类方法可以根据提供的参数构建一个请求。


application(cls, f)


@classmethod

def application(cls, f):

    """Decorate a function as responder that accepts the request as first

    argument.  This works like the :func:`responder` decorator but the

    function is passed the request object as first argument and the

    request object will be closed automatically::

        @Request.application

        def my_wsgi_app(request):

            return Response('Hello World!')

    :param f: the WSGI callable to decorate

    :return: a new WSGI callable

    """

    #: return a callable that wraps the -2nd argument with the request

    #: and calls the function with all the arguments up to that one and

    #: the request.  The return value is then called with the latest

    #: two arguments.  This makes it possible to use this decorator for

    #: both methods and standalone WSGI functions.

    def application(*args):

        request = cls(args[-2])

        with request:

            return f(*args[:-2] + (request,))(*args[-2:])

    return update_wrapper(application, f)


这个类方法是一个装饰器,可以用来装饰WSGI可调用对象或函数。


以上属性和方法的具体用法可以参考Request——werkzeug文档。


BaseResponse


BaseResponse类是一个响应类,用它可以封装一个response对象。response对象最大的特点是它是一个WSGI应用。


在之前介绍WSGI规范的文章中曾介绍过Web服务器网关,它简化了服务器和web应用之间的通信过程,它要求服务器和web应用要遵循WSGI规范进行开发。对于web应用而言,应用应该实现一个函数或者一个可调用对象,这样WSGI服务器可以通过调用myWebApp(environ, start_response)从web应用获得响应内容。


response响应对象就是这样一个WSGI应用对象。在其实现过程中有一个__call__方法,可以实现对一个response对象的调用。代码如下:


def __call__(self, environ, start_response):

    """Process this response as WSGI application.

    :param environ: the WSGI environment.

    :param start_response: the response callable provided by the WSGI

                           server.

    :return: an application iterator

    """

    app_iter, status, headers = self.get_wsgi_response(environ)

    start_response(status, headers)

    return app_iter


这样,我们就可以很清楚地理解WSGI应用的实现过程。下面是一个非常简单的WSGI应用。


from werkzeug.wrappers import Request, Response

def application(environ, start_response):

    request = Request(environ)

    response = Response("Hello %s!" % request.args.get('name', 'World!'))

    return response(environ, start_response)


上面的小例子的实现步骤分析:


  1. 根据传入web应用的environ构造请求对象request;

  2. web应用构造响应对象response;

  3. 调用响应对象response。调用过程中产生三个值:app_iter、status、headers,其中status和headers作为参数传递给函数start_response用于生成响应报文首行的相关信息,而app_iter作为响应的内容(它是一个可迭代对象)返回给WSGI网关;

  4. WSGI网关将返回的信息组成响应首行、响应首部、响应主体等,形成响应报文发回给客户端。


BaseResponse类中还有一些属性和方法,以下属性和方法的具体用法可以参考Response——werkzeug文档。


  • 属性

    • status_code

    • status

    • data

    • is_stream

    • is_sequence

    • ······

  • 方法

    • call_on_close(func)

    • close()

    • freeze()

    • force_type() 类方法

    • from_app() 类方法

    • set_data()

    • get_data()

    • _ensure_sequence()

    • make_sequence()

    • iter_encoded()

    • calculate_content_length()

    • set_cookie()

    • delete_cookie()

    • get_wsgi_headers(environ)

    • get_app_iter(environ)

    • get_wsgi_response(environ)

    • __call__(environ, start_response)

    • ······

Mixin类


BaseRequest类和BaseResponse类是请求和响应最基础的类。wrappers模块中还提供了一些Mixin类,用于扩展请求类和响应类。


有关请求类的Mixin类


有关请求类的Mixin类主要有:


  • AcceptMixin类 ——请求报文中关于客户端希望接收的数据类型的类。

  • ETagRequestMixin类 ——请求报文中关于Etag和Cache的类。

  • UserAgentMixin类 ——请求报文中关于user_agent的类。

  • AuthorizationMixin类 ——请求报文中关于认证的类。

  • CommonRequestDescriptorsMixin类 ——通过这个类可以获取请求首部中的相关信息。


有关响应类的Mixin类


有关响应类的Mixin类主要有:


  • ETagResponseMixin类 ——为响应增加Etag和Cache控制的类。

  • ResponseStreamMixin类 ——为响应可迭代对象提供一个“只写”的接口的类。

  • CommonResponseDescriptorsMixin类 ——通过这个类可以获取响应首部中的相关信息。

  • WWWAuthenticateMixin类 ——为响应提供认证的类。


Request和Response


终于讲到Request类和Response类了。


Request类继承自BaseRequest类,并且结合一些请求相关的Mixin类,具体如下:


class Request(BaseRequest, AcceptMixin, ETagRequestMixin,

              UserAgentMixin, AuthorizationMixin,

              CommonRequestDescriptorsMixin)


Response类继承自BaseResponse类,并且结合一些响应相关的Mixin类,具体如下:


class Response(BaseResponse, ETagResponseMixin, ResponseStreamMixin,

               CommonResponseDescriptorsMixin,

               WWWAuthenticateMixin)


至此,可以从wrappers模块中引入Request类和Response用于构建请求对象和响应对象。

你可能感兴趣的:(Python)