01. Flask源码分析之【werkzurg】
1.1 引子
我们知道所有的 python web 框架都要遵循 WSGI 协议,而Flask本身并没有,而是依赖werkzeug实现的
那么先抛开Flask不谈,通过一段简单的代码,看看werkzeug的作用
from werkzeug.serving import run_simple
def func(environ, start_response):
print("请求来了")
pass
if __name__ == '__main__':
run_simple('127.0.0.1', 5000, func)
- 访问127.0.0.1: 5000可以打印出来"请求来了",说明,请求进来后,会执行
func(), - 同理,如果
run_simple()中的func是个app对象,则执行app()就会执行app对象的__call__方法
所以可写为:
from werkzeug.serving import run_simple
class Flask(object):
def __call__(self, environ, start_response):
return '来了啊狗子'
app = Flask()
if __name__ == '__main__':
run_simple('127.0.0.1', 5000, app)
1.2 flask快速上手
一个最小的 Flask 应用如下:
from flask import Flask, render_template
# 1.创建app
app = Flask(__name__)
# app是Flask的实例,它接收包或者模块的名字作为参数,但一般都是传递__name__。
# 有了这个参数, Flask 才能知道在哪里可以找到模板和静态文件等东西。
# 2.路由和视图
@app.route('/index')
def login():
return 'hello world'
if __name__ == '__main__':
app.run()
应用启动的代码是 app.run(),源码解析如下(简化):
def run(self, host=None, port=None, debug=None, **options):
# 如果host 和 port 没有指定,则设置 host 和 port 的默认值 127.0.0.1 和 5000
if not host:
if sn_host:
host = sn_host
else:
host = "127.0.0.1"
if port or port == 0:
port = int(port)
elif sn_port:
port = int(sn_port)
else:
port = 5000
# 调用 werkzeug.serving 模块的 run_simple 函数,传入收到的参数
# 注意第三个参数传进去的是 self,也就是要执行的 app
try:
run_simple(host, port, self, **options)
finally:
self._got_first_request = False
概括:
- flask是依赖werkzurg实现wsgi,flask自己没有wsgi
- 请求一旦进来,就会执行
app.__call__方法
接下来看看Flask类中的两个方法:
class Flask(Scaffold):
def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
ctx = self.request_context(environ)
error: t.Optional[BaseException] = None
try:
try:
ctx.push()
# 正确的请求处理路径,会通过路由找到对应的视图函数
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
return self.wsgi_app(environ, start_response)
果然有__call__方法,从它入手!那么上面这段代码简单概括就是:找到视图函数,然后调用它。
除了异常处理之外,我们还看到了 context 相关的内容(开始有 ctx.push(),最后有 ctx.auto_pop()的逻辑),后面再介绍。
浙公网安备 33010602011771号