专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python爱好者社区  ·  国企官网被挂上“码农的钱你也敢吞,还钱” ·  昨天  
Python中文社区  ·  揭秘 DeepSeek ... ·  2 天前  
Python开发者  ·  DeepSeek 下棋靠忽悠赢了 ... ·  4 天前  
Python爱好者社区  ·  “给我滚出贵大!”郑强出任贵州大学校长,打算 ... ·  5 天前  
Python爱好者社区  ·  DeepSeek 最新中国大学排名 ·  2 天前  
51好读  ›  专栏  ›  Python开发者

flask 源码解析:应用启动流程

Python开发者  · 公众号  · Python  · 2017-03-08 21:16

正文

(点击 上方蓝字 ,快速关注我们)


来源:cizixs

segmentfault.com/a/1190000008409802

如有好文章投稿,请点击 → 这里了解详情


WSGI


所有的 python web 框架都要遵循 WSGI 协议,如果对 WSGI 不清楚,可以查看《 python wsgi 简介 》。


在这里还是要简单回顾一下 WSGI 的核心概念。


WSGI 中有一个非常重要的概念:每个 python web 应用都是一个可调用(callable)的对象。在 flask 中,这个对象就是 app = Flask(__name__) 创建出来的 app,就是下图中的绿色 Application 部分。要运行 web 应用,必须有 web server,比如我们熟悉的 apache、nginx ,或者 python 中的 gunicorn ,我们下面要讲到的 werkzeug 提供的 WSGIServer,它们是下图的黄色 Server 部分。



图片来源(https://www.toptal.com/python/pythons-wsgi-server-application-interface)


Server 和 Application 之间怎么通信,就是 WSGI 的功能。它规定了 app(environ, start_response) 的接口,server 会调用 application,并传给它两个参数:environ 包含了请求的所有信息,start_response 是 application 处理完之后需要调用的函数,参数是状态码、响应头部还有错误信息。


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 ()


这里的 app = Flask(__name__) 就是上面提到的 Application 部分,但是我们并没有看到 Server 的部分,那么它一定是隐藏到 app.run() 内部某个地方了。


启动流程


应用启动的代码是 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:为了阅读方便,我删除了注释和不相干的部分,下面所有的代码都会做类似的处理,不再赘述。


这个方法的内容非常简单:处理一下参数,然后调用 werkzeug 的 run_simple。需要注意的是:run_simple 的第三个参数是 self,也就是我们创建的 Flask() application。因为 WSGI server 不是文章的重点,所以我们就不深入讲解了。现在只需要知道它的功能就行:监听在指定的端口,收到 HTTP 请求的时候解析为 WSGI 格式,然后调用 app 去执行处理的逻辑。对应的执行逻辑在 werkzeug.serving:WSGIRequestHandler 的 run_wsgi 中有这么一段代码:


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


可以看到 application_iter = app(environ, start_response) 就是调用代码获取结果的地方。


要调用 app 实例,那么它就需要定义了 __call__ 方法,我们找到 flask.app:Flask 对应的内容:


def __call__ ( self , environ , start_response ) :

"""Shortcut for :attr:`wsgi_app`."""

return self . wsgi_app ( environ , start_response )

def wsgi_app ( self , environ , 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







请到「今天看啥」查看全文