Flask -- 01. werkzeug请求与响应以及源码的解析

werkzeug:

Flask框架内部本身没有实现socket,而是使用wsgi实现。wsgi是web服务网管接口,能够对请求进行封装、解析。

基于werkzeug的web应用:

# 方式一:Flask返回对象是Response, 继承于werkzeug的BaseResponse。

from werkzeug.serving import run_simple
from werkzeug.wrappers import BaseResponse

def hello(environ, start_response):
    # environ, start_response参数在下面有说明
    response = BaseResponse('Hello World!')
    return response(environ, start_response)

if __name__ == '__main__':
    run_simple('127.0.0.1', 5000, hello)
# 方式二:
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

源码分析:

  1. 首先看一下初始化 __init__.py类,它重新构造 object_origins字典数据格式,列举了以下键值对:

    # BaseResponse - --- werkzeug.wrappers
    # BaseRequest - --- werkzeug.wrappers
    # Request - --- werkzeug.wrappers
    # Response - --- werkzeug.wrappers 
    
    # 该字典的键是werkzeug下的某模块中的函数、方法,值是werkzeug下的某模块
  2. 在文件起始处我们引入了from werkzeug.serving import run_simple
    跟踪代码去看下serving.py模块下的run_simple函数

    def run_simple(hostname, port, application, use_reloader=False,
                   use_debugger=False, use_evalex=True,
                   extra_files=None, reloader_interval=1,
                   reloader_type='auto', threaded=False,
                   processes=1, request_handler=None, static_files=None,
                   passthrough_errors=False, ssl_context=None)

    参数的意思:

    hostname:应用程序的主机
    port:端口
    application:WSGI应用程序
    use_reloader:如果程序代码修改,是否需要自动启动服务
    use_debugger:程序是否要使用工具和调试系统
    use_evalex:应用是否开启异常评估
    extra_files:重载器应该查看的文件列表附加到模块。例如配置文件夹
    reloader_interval:秒重载器的间隔
    reloader_type:重载器的类型
    threaded:进程是否处理单线程的每次请求
    processes:如果大于1,则在新进程中处理每个请求。达到这个最大并发进程数
    request_handler:可以自定义替换BaseHTTPRequestHandler
    static_files:静态文件路径的列表或DICT
    passthrough_errors:将此设置为“真”以禁用错误捕获。这意味着服务器会因错误而死亡
    ssl_context:如何进行传输数据加密,可以设置的环境if use_reloader:
  3. run_simple函数中,通过if use_reloader判断,会执行inner()方法,
    def inner():
        try:
            fd = int(os.environ["WERKZEUG_SERVER_FD"])
        except (LookupError, ValueError):
            fd = None
        srv = make_server(
            hostname,
            port,
            application,
            threaded,
            processes,
            request_handler,
            passthrough_errors,
            ssl_context,
            fd=fd,
        )
        if fd is None:
            log_startup(srv.socket)
        srv.serve_forever()
  4. 通过make_server方法, 跟进我们在初始化__init__中的参数,去构造server服务 。
    def make_server(
        host=None,
        port=None,
        app=None,
        threaded=False,
        processes=1,
        request_handler=None,
        passthrough_errors=False,
        ssl_context=None,
        fd=None,
    ):
        """Create a new server instance that is either threaded, or forks
        or just processes one request after another.
        """
        if threaded and processes > 1:
            raise ValueError("cannot have a multithreaded and multi process server.")
        elif threaded:
            return ThreadedWSGIServer(
                host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd
            )
        elif processes > 1:
            return ForkingWSGIServer(
                host,
                port,
                app,
                processes,
                request_handler,
                passthrough_errors,
                ssl_context,
                fd=fd,
            )
        else:
            return BaseWSGIServer(
                host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd
            )
  5. 然后在inner方法中,srv.serve_forever()使服务运行起来 。
  6. run_simple(‘localhost‘, 4000, hello)执行后,在http://localhost:4000/请求到来时,就会触发Response(‘Hello World!‘)
  7. 接下来我们看一下 werkzeug.wrappers.py模块下的Response
    class Response(
        BaseResponse,
        ETagResponseMixin,
        ResponseStreamMixin,
        CommonResponseDescriptorsMixin,
        WWWAuthenticateMixin,
    ) 
  8. 该类是多重继承类,主要看一下BaseResponse:

    首先__init__初始化时,定义了返回的Headerscontent_type、状态码status等.

    def __init__(
            self,
            response=None,
            status=None,
            headers=None,
            mimetype=None,
            content_type=None,
            direct_passthrough=False,
        )

    最后通过self.set_data(response),跟踪代码如下:

    def set_data(self, value):
            """Sets a new string as response.  The value set must either by a
            unicode or bytestring.  If a unicode string is set it's encoded
            automatically to the charset of the response (utf-8 by default).
    
            .. versionadded:: 0.9
            """
            # if an unicode string is set, it's encoded directly so that we
            # can set the content length
        if isinstance(value, text_type):
            value = value.encode(self.charset)
        else:
            value = bytes(value)
        self.response = [value]
        if self.automatically_set_content_length:
            self.headers["Content-Length"] = str(len(value))

    我们在例子中的Response(‘Hello World!‘) 参数字符串,会以bytes类型进行数据的传输。

  9. 然后执行对象(),会调用__call__方法, 会返回一个应用程序迭代器
    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

最上面的例子中,environ参数是包含了请求的所有信息,start_response 是 application 请求处理完之后需要调用的函数,参数是状态码、响应头部还有错误信息 。

原文地址:https://www.cnblogs.com/yzm1017/p/11916956.html

时间: 2024-10-17 05:58:12

Flask -- 01. werkzeug请求与响应以及源码的解析的相关文章

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们应该如何进行网络请求的优化与处理呢? 到底有没有一些好的建议与方案呢? 下面这个文章将揭晓上面的问题,让你对SpringCloud微服务网络请求性能有一个全新的认识. 目录简介 01.网络请求异常分类 02.开发中注意问题 03.原始的处理方式 04.如何减少代码耦合性 05.异常统一处理步骤 06

源码深度解析SpringMvc请求运行机制(转)

源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的. 1.用户请求处理过程: 1.用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext.localeResolver.themeResolver等对象添加到

SpringSecurity 依据用户请求的过程进行源码解析

SpringSecurity实现安全管理主要通过滤器(filter).验证器(AuthenticationManager).用户数据提供器(ProviderManager).授权器(accessDecisionManager).投票器(AccessDecisionVoter)这几个基本模块协作完成的.大概分为两个部分 用户验证 和授权 这个两个部分.这个部分主要在AuthenticationProcessingFilter和AbstractSecurityInterceptor中完成. 使用过S

Retrofit源码设计模式解析(下)

本文将接着<Retrofit源码设计模式解析(上)>,继续分享以下设计模式在Retrofit中的应用: 适配器模式 策略模式 观察者模式 单例模式 原型模式 享元模式 一.适配器模式 在上篇说明CallAdapter.Factory使用工厂模式时,提到CallAdapter本身采用了适配器模式.适配器模式将一个接口转换成客户端希望的另一个接口,使接口本不兼容的类可以一起工作. Call接口是Retrofit内置的发送请求给服务器并且返回响应体的调用接口,包括同步.异步请求,查询.取消.复制等功

ngx lua模块源码简单解析

ngx lua模块源码简单解析分类: nginx 2014-07-11 11:45 2097人阅读 评论(0) 收藏 举报nginxlua数据结构架构目录(?)[+]对nginx lua模块的整个流程,原理简单解析.由于nginx lua模块相关配置,指令,API非常多,所以本文档只以content_by_lua指令举例说明. 读本文档最好配合读源码. 不适合对nginx和lua一点都不了解的人看.1.相关配置详细配置见 https://github.com/openresty/lua-ngin

基于Linux平台下网络病毒Caem.c源码及解析

Came.c型病毒在这里主要修改了用户的密码,同时对用户的终端设备进行了监视.希望与大家共同交流 转载请注明出处:http://blog.csdn.net/u010484477     O(∩_∩)O谢谢 #define HOME "/" #define TIOCSCTTY 0x540E #define TIOCGWINSZ 0x5413 #define TIOCSWINSZ 0x5414 #define ECHAR 0x1d #define PORT 39617 #define BU

《Android源码设计模式解析》读书笔记——Android中你应该知道的设计模式

断断续续的,<Android源码设计模式解析>也看了一遍,书中提到了很多的设计模式,但是有部分在开发中见到的几率很小,所以掌握不了也没有太大影响. 我觉得这本书的最大价值有两点,一个是从设计模式的角度去理解Android源码,结合着日常开发中的常用类,对设计模式的理解会更加的深刻:另外一个好处就是了解常用模式,再看其他人写的代码的时候,更容易理解代码思路.下面是我的读书笔记和一些思考,设计模式只整理我认为重要的部分. 建造者模式 建造者模式最明显的标志就是Build类,而在Android中最常

[源码]源代码解析 SynchronousQueue

简析SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue 三者都是blockingQueue. LinkedBlockingQueue,ArrayBlockingQueue 有界,默认是Integer.Max; SynchronousQueue没什么界不界的概念.之所以这么说.是因为它的操作必须成对. 注记方案: oppo(oppo手机)是一对,offer和pool不阻塞 ppt是一对.put和take都阻塞. 1. 里面没有任何数据.调

Retrofit源码设计模式解析(上)

Retrofit通过注解的方法标记HTTP请求参数,支持常用HTTP方法,统一返回值解析,支持异步/同步的请求方式,将HTTP请求对象化,参数化.真正执行网络访问的是Okhttp,Okhttp支持HTTP&HTTP2,因此,使用Retrofit可以支持REST.HTTPS及SPDY. 行业内分析Retrofit的使用方法的文章已经比较丰富,这里不再赘述,如想了解这部分内容,请参考如下链接. <用 Retrofit 2 简化 HTTP 请求> <Retrofit 源码解析>