美文网首页程序员
flask源码笔记(2) 最简单的flask app分析

flask源码笔记(2) 最简单的flask app分析

作者: kuulid | 来源:发表于2017-10-08 21:06 被阅读137次

    github地址:包括所有实例的代码 https://github.com/kurset/learn_flask_code
    不定期更新。


    下面我们尝试分析一下一个最简单的flask应用都发生了什么

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello():
        return 'hello world'
    
    if __name__ == '__main__':
        app.run()
    

    大致这段程序flask要做四件事情

    1. 初始化Flask的对象
    2. 建立url和对应的视图处理函数
    3. 启动一个flask的开发服务器
    4. 解析请求url并调用相应的视图处理函数

    初始化Flask的对象

    在源码中,Flask类位于app.py中,是最重要的类,大约有两千多行代码,先来看看__init__方法

     def __init__(self, import_name, static_path=None, static_url_path=None,
                     static_folder='static', template_folder='templates',
                     instance_path=None, instance_relative_config=False,
                     root_path=None):
    

    基本上只需要传入一个模块名,其他的一些设置项都有自己的默认值。但这个方法里面初始化有些数据很重要,比如

    self.view_functions = {}
    self.url_map = Map()
    

    大概也能看出来,这分别保存了Flask对象的url数据结构和视图函数。

    建立url和对应的视图处理函数

    Flask是如何建立url和视图处理函数呢
    当然是找route的装饰器了。装饰器定义很简单

        def route(self, rule, **options):
            def decorator(f):
                endpoint = options.pop('endpoint', None)
                self.add_url_rule(rule, endpoint, f, **options)
                return f
            return decorator
    

    就是取出endpoint的设置项,并进行add_url_rule的操作。
    那么endpoint是什么呢,我们可以把它看做是url_map和view_function对应的key值,通过这个值,把url和视图函数联系起来。但一般我们并没有设置这个值,在add_url_rule函数中,我们可以看到Flask调用了_endpoint_from_view_func方法,实际上endpoint取的是view_func.name
    接下来,在add_url_rule方法中可以看到

    rule = self.url_rule_class(rule, methods=methods, **options)
    rule.provide_automatic_options = provide_automatic_options
    
    self.url_map.add(rule)
    

    url_rule_class是Flask封装的一个Rule的Class

    url_rule_class = Rule
    

    新初始化一个rule的class并加入到url_map中。

    启动一个flask的开发服务器

    这个说法并不准确,因为当我们看Flask类中run()方法时候,可以看到Flask的开发服务器实际上是werkzeug提供的。

    # run方法中 简化代码
    from werkzeug.serving import run_simple
    run_simple(host, port, self, **options)
    

    解析请求url并调用相应的视图处理函数

    这是一个比较麻烦的过程,先从Flask的wsgi_app看起,从wsgi中接到environ基本的请求信息,Flask首先保存请求信息并压入请求栈中,这个细节先不去探究

    ctx = self.request_context(environ)
    ctx.push()
    

    之后调用full_dispatch_request方法,处理请求。
    在full_dispatch_request里调用full_dispatch_request方法

        def dispatch_request(self):
            req = _request_ctx_stack.top.request
            if req.routing_exception is not None:
                self.raise_routing_exception(req)
            rule = req.url_rule
            # if we provide automatic options for this URL and the
            # request came with the OPTIONS method, reply automatically
            if getattr(rule, 'provide_automatic_options', False) \
               and req.method == 'OPTIONS':
                return self.make_default_options_response()
            # otherwise dispatch to the handler for that endpoint
            return self.view_functions[rule.endpoint](**req.view_args)
    

    可以看到先从当前的请求上下文中找到request信息,之后在request信息中保留url的endpoint,再从view_functions里面根据endpoint找到视图函数,并返回执行结果。
    full_dispatch_request最后会调用一个finalize_request方法,将结果包装成response_class,最终返回给用户。

        def finalize_request(self, rv, from_error_handler=False):
            response = self.make_response(rv)
            try:
                response = self.process_response(response)
                request_finished.send(self, response=response)
            except Exception:
                if not from_error_handler:
                    raise
                self.logger.exception('Request finalizing failed with an '
                                      'error while handling an error')
            return response
    

    相关文章

      网友评论

        本文标题:flask源码笔记(2) 最简单的flask app分析

        本文链接:https://www.haomeiwen.com/subject/cxlyyxtx.html