flask 源码解析:应用启动流程
这是 flask 源码解析系列文章的其中一篇,本系列所有文章列表:
WSGI所有的 python web 框架都要遵循 WSGI 协议,如果对 WSGI 不清楚,可以查看我之前的介绍文章。 在这里还是要简单回顾一下 WSGI 的核心概念。 WSGI 中有一个非常重要的概念:每个 python web 应用都是一个可调用(callable)的对象。在 flask 中,这个对象就是? NOTE:?图片来源。 Server 和 Application 之间怎么通信,就是 WSGI 的功能。它规定了? WSGI application 非常重要的特点是:它是可以嵌套的。换句话说,我可以写个 application,它做的事情就是调用另外一个 application,然后再返回(类似一个 proxy)。一般来说,嵌套的最后一层是业务应用,中间就是 middleware。这样的好处是,可以解耦业务逻辑和其他功能,比如限流、认证、序列化等都实现成不同的中间层,不同的中间层和业务逻辑是不相关的,可以独立维护;而且用户也可以动态地组合不同的中间层来满足不同的需求。 WSGI 的内容就讲这么多,我们来看看 flask 的 hello world 应用: 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,?**options): ????"""Runs?the?application?on?a?local?development?server.""" ????from?werkzeug.serving?import?run_simple????#?如果host?和?port?没有指定,设置?host?和?port?的默认值?127.0.0.1?和?5000 ????if?host?is?None: ????????host?=?'127.0.0.1' ????if?port?is?None: ????????server_name?=?self.config['SERVER_NAME'] ????????if?server_name?and?':'?in?server_name: ????????????port?=?int(server_name.rsplit(':',?1)[1]) ????????else: ????????????port?=?5000 ????#?调用?werkzeug.serving?模块的?run_simple?函数,传入收到的参数 ????#?注意第三个参数传进去的是?self,也就是要执行的?web?application ????try: ????????run_simple(host,?port,?self,?**options) ????finally: ????????self._got_first_request?=?False NOTE:为了阅读方便,我删除了注释和不相干的部分,下面所有的代码都会做类似的处理,不再赘述。 这个方法的内容非常简单:处理一下参数,然后调用? def?execute(app): ????application_iter?=?app(environ,?start_response) ????try: ????????for?data?in?application_iter: ????????????write(data) ????????if?not?headers_sent: ????????????write(b'') ????finally: ????????if?hasattr(application_iter,?'close'): ????????????application_iter.close() ????????????application_iter?=?None 可以看到? 要调用? def?__call__(self,?environ,?start_response): ????"""Shortcut?for?:attr:`wsgi_app`.""" ????return?self.wsgi_app(environ,?start_response)def?wsgi_app(self,?start_response): ????"""The?actual?WSGI?application. ????""" ????#?创建请求上下文,并把它压栈。这个在后面会详细解释 ????ctx?=?self.request_context(environ) ????ctx.push() ????error?=?None ????try: ????????try: ????????????#?正确的请求处理路径,会通过路由找到对应的处理函数 ????????????response?=?self.full_dispatch_request() ????????except?Exception?as?e: ????????????#?错误处理,默认是?InternalServerError?错误处理函数,客户端会看到服务器?500?异常 ????????????error?=?e ????????????response?=?self.handle_exception(e) ????????return?response(environ,?start_response) ????finally: ????????if?self.should_ignore_error(error): ????????????error?=?None ????????#?不管处理是否发生异常,都需要把栈中的请求?pop?出来 ????????ctx.auto_pop(error) 上面这段代码只有一个目的:找到处理函数,然后调用它。除了异常处理之外,我们还看到了? 继续往后看, def?full_dispatch_request(self): ????"""Dispatches?the?request?and?on?top?of?that?performs?request ????pre?and?postprocessing?as?well?as?HTTP?exception?catching?and ????error?handling. ????""" ????self.try_trigger_before_first_request_functions() ????try: ????????request_started.send(self) ????????rv?=?self.preprocess_request() ????????if?rv?is?None: ????????????rv?=?self.dispatch_request() ????except?Exception?as?e: ????????rv?=?self.handle_user_exception(e) ????return?self.finalize_request(rv) 这段代码最核心的内容是? NOTE: 在?
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |