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)
运行代码后,浏览器访问,可以发现传入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__()方法
同样的,当请求过来时,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()
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
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)
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)
https://werkzeug-docs-cn.readthedocs.io/zh_CN/latest/tutorial.html

浙公网安备 33010602011771号