A request to flask
2015-12-09有感于之前看到的 repo: what-happens-when
What happens when you type google.com into your browser and press enter?
于是决定今天来说说当一个普通的 Get 请求来的时候, Flask 中到底发生了什么事情。 我以最简单的 Hello word 的例子来说明, 当我们访问 http://localhost:5000/ 时, Flask 的内部处理是怎样的。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello, world.'
if __name__ == '__main__':
app.run(debug=True)
当然,只是个人理解,错误指出还请指出来 _(:3
简单概括
- preprocess request
- url map, dispatch request
- postprocess response
具体展开
简单来说就是依据 request 的 URL 找到对应绑定的 view function [1],执行然后返回 response 就行。 最基本的简单思路大致是这样。在 Opening The Flask 中,简化版本的 flask 例子中的思路就是这样。
from werkzeug import Request, Response, run_simple
from werkzeug.exceptions import HTTPException
from werkzeug.routing import Map, Rule
class YourFlask(object):
def __init__(self):
self.url_map = Map()
self.views = {}
def route(self, string, **options):
def decorator(f):
options['endpoint'] = f.__name__
self.views[f.__name__] = f
self.url_map.add(Rule(string, **options))
return f
return decorator
def run(self, **options):
return run_simple('localhost', 5000, self, **options)
def make_response(self, rv):
if isinstance(rv, basestring):
return Response(rv, mimetype='text/html')
return rv
def __call__(self, environ, start_response):
request = Request(environ)
adapter = self.url_map.bind_to_environ(environ)
try:
endpoint, values = adapter.match()
response = self.make_response(self.views[endpoint](request, **values))
except HTTPException, e:
response = e
return response(environ, start_response)
以上的是使用 werkzeug 这个库写的一个简单的 web framework,但是基本把 flask 的思路表现出来了。
现实中的 flask 也是采用类似的思路,加上请求预处理和响应后处理。接下来以 flask 0.1 版本来说明一下:
def wsgi_app(self, environ, start_response):
with self.request_context(environ):
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
response = self.make_response(rv)
response = self.process_response(response)
return response(environ, start_response)
可以看到,首先是请求的预处理 self.preprocess_request()。这会把我们使用 before_request 注册的函数依次调用一遍, 比如说数据库的连接或者相关数据的预处理等等。值得注意的是,如果在预处理时有有效的结果,这时候是会跳过将请求分发给 view 函数这一步, 也就是说 URL 对应的 view 函数将不会执行。然后是调用 make_response 将返回的结果转换成一个有效的 response object。 接下来是响应后处理。同预处理一样,会将我们使用 after_request 注册的函数依次调用,比如说断开数据库的 连接等操作。
在目前的 flask 0.10.1 版本中,主要代码逻辑是这样的:
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.make_response(self.handle_exception(e))
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
其相对与 0.1 的变化有:
- 更为完善的错误异常处理
- blueprint 的相关处理(new in 0.7) [2]
- signal 处理相关(new in 0.6) [3]
- 请求预处理中,先会调用 url_value_processor 注册的函数(new in 0.7) [4]
- 最后会把 request context pop 掉,在 pop 时,调用 do_teardown_request (使用 tear_down_request 注册的函数), 有必要是也会把 app context pop 掉(会调用 do_teardown_appcontext)
总结
总结一下,一个简单的请求在 flask 中的过程:
- preprocess request
- url value process
- before request hooks
- url map, dispatch request
- postprocess response
- after request hooks
- pop request context/app context
参考
- Opening The Flask: Flask 作者的一篇博文
- Flask v0.1: 0.1 的版本,但是基本的样子都有了。
| [1] | 关于 flask 路由的问题不在这里展开,我的 wiki 有总结 http://wiki.lord63.com/python/flask/flask_route.html |
| [2] | 在 preprocess_request 中可以看到相关代码。 |
| [3] | 在 full_dispatch_request 中可以看到相关代码。 |
| [4] | 在 preprocess_request 中可以看到相关代码。 |