flask源码学习

      flask借助了jinja2模板和Werkzeug WSGI服务,Werkzeug本质上是一个Socket,类似于WSGI server,接收http请求并进行预处理,然后调用flask处理相应的请求。先看一段利用Werkzeug的代码

#coding:utf-8

from werkzeug.wrappers import Request,Response
from werkzeug.serving import run_simple

@Request.application
def hello(request):
    return Response("hello world")

if __name__=="__main__":
    run_simple("127.0.0.1", 8000,hello)
View Code

  运行代码后,浏览器访问,可以发现传入run_simple的hello函数被执行了。进一步看下面这个代码:

from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple

class Shortly(object):
    def __init__(self,name):
        self.name = name

    def dispatch_request(self,request):
        return Response("Hello World")

    def wsgi_app(self,environ,start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ,start_response)

    def __call__(self, environ,strat_reponse):
        return self.wsgi_app(environ,strat_reponse)

if __name__ =="__main__":
    app = Shortly(__name__)

    run_simple("127.0.0.1",5000,app)  #请求进来,调用app(),即调用Shortly类的__call__()方法
View Code

  同样的,当请求过来时,run_simple的app()被执行,即对应的Shortly类的__call__()方法被执行,而且注意到其接受到的两个参数environ, start_response,即为WSGI规范中需要传入的两个参数。另外,分别利用Werkzeug提供的Request, Response类对environ和response进行了封装。

  接下来看下flask应用的代码和部分flask源码,可以发现请求进来是执行流程如下:

       app.run()---------run_simple(host,port,app)-----------__call__(ienviron,start_reponse)----------------------wsgi_app(ienviron,start_reponse)

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run()
View Code
    def run(self, host=None, port=None, debug=None,
            load_dotenv=True, **options):
        
        if os.environ.get('FLASK_RUN_FROM_CLI') == 'true':
            from .debughelpers import explain_ignored_app_run
            explain_ignored_app_run()
            return

        if get_load_dotenv(load_dotenv):
            cli.load_dotenv()

            # if set, let env vars override previous values
            if 'FLASK_ENV' in os.environ:
                self.env = get_env()
                self.debug = get_debug_flag()
            elif 'FLASK_DEBUG' in os.environ:
                self.debug = get_debug_flag()

        # debug passed to method overrides all other sources
        if debug is not None:
            self.debug = bool(debug)

        _host = '127.0.0.1'
        _port = 5000
        server_name = self.config.get('SERVER_NAME')
        sn_host, sn_port = None, None

        if server_name:
            sn_host, _, sn_port = server_name.partition(':')

        host = host or sn_host or _host
        port = int(port or sn_port or _port)

        options.setdefault('use_reloader', self.debug)
        options.setdefault('use_debugger', self.debug)
        options.setdefault('threaded', True)

        cli.show_server_banner(self.env, self.debug, self.name, False)

        from werkzeug.serving import run_simple

        try:
            run_simple(host, port, self, **options)
        finally:
            # reset the first request information if the development server
            # reset normally.  This makes it possible to restart the server
            # without reloader and that stuff from an interactive shell.
            self._got_first_request = False
Flask类的run()源码
    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)
Flask类__call__()方法源码
    def wsgi_app(self, environ, start_response):
       
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
Flask类wsgi_app()源码

 

https://werkzeug-docs-cn.readthedocs.io/zh_CN/latest/tutorial.html

posted @ 2024-09-21 14:17  silence_cho  阅读(58)  评论(0)    收藏  举报