Flask是python web框架,主要包含werkzeug和jinja2,前者是一个WSGI工具集,后者用来实现模板处理。
WSGI(Web Server Gateway Interface)是一个协议,定义了Web Server和app之间的接口。接口很简单,下面一个例子myapp.py:
def app(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return 'Hello, web!
'
# gunicorn myapp:app
gunicorn在这里作为一个WSGI web server,通过上面的命令就可以启动这个app。关于WSGI详细信息可以参考廖雪峰的官方网站
Werkzeug 并不是 一个框架,它是一个 WSGI 工具集的库,你可以通过它来创建你自己的框架或 Web 应用。
Werkzeug提供了一系列工具,使WSGI编程更简单,下面一个列子:
from werkzeug.wrappers import Request, Response
def application(environ, start_response):
request = Request(environ)
text = 'Hello %s!' % request.args.get('name', 'World')
response = Response(text, mimetype='text/plain')
return response(environ, start_response)
上面的例子中通过Request和Response,使app代码更加pythonic。还有一些有效的工具,用来实现路由等功能,这些在flask中都有应用:
from werkzeug.routing import Map, Rule
关于Werkzeug详细信息可以参考Werkzeug教程
模板处理是flask的核心功能之一,用来处理网页模板:
from jinja2 import Template
t = Template("{{ name }}, hello jinja2 world!")
t.render(name='Mr. Y') #u'Mr. Y, hello jinja2 world!'
关于jiaja2详细信息可以参考欢迎来到 Jinja2
Flask参考资料flask,官网有一个最简单app:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
0.1版代码量最小,只有几百行实现了所有核心功能。就用这个app去分析0.1版代码(这个APP不涉及模板)
from flask import Flask
app = Flask(__name__)
flask.py
class Flask(object):
def __init__(self, package_name):
#包名
self.package_name = package_name
#根路径
self.root_path = _get_package_path(self.package_name)
#视图函数,即例子中的hello_world函数
self.view_functions = {}
#错误处理函数,Key是错误状态码,Value是处理函数
self.error_handlers = {}
#预处理函数列表
self.before_request_funcs = []
#后处理函数列表
self.after_request_funcs = []
#url到视图函数的映射
self.url_map = Map()
@app.route('/')
def hello_world():
return 'Hello World!'
flask.py
def route(self, rule, **options):
def decorator(f):
self.add_url_rule(rule, f.__name__, **options)
self.view_functions[f.__name__] = f
return f
return decorator
def add_url_rule(self, rule, endpoint, **options):
options['endpoint'] = endpoint
options.setdefault('methods', ('GET',))
self.url_map.add(Rule(rule, **options))
route是一个修饰器,功能就是完成url_map和view_functions的初始化,其中Rule是werkzeug提供的工具。
if __name__ == '__main__':
app.run()
app运行时的调用顺序是:
run
--> werkzeug.run_simple
--> __call__(self, environ, start_respones)
--> wsgi_app(environ, start_response)
__call__()函数很简单,核心是wsgi_app:
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):
#初始化请求,3.2节分析
with self.request_context(environ):
#预处理,hello_world例子中不包含
rv = self.preprocess_request()
#分发请求,3.3节分析
if rv is None:
rv = self.dispatch_request()
response = self.make_response(rv)
#后处理,hello_world例子中不包含
response = self.process_response(response)
#响应
return response(environ, start_response)
请求上下文调用顺序,请求保存在_request_ctx_stack中,LocalStack由werkzeug提供,并保证线程安全。
request_context
--> _RequestContext(self, environ)
class _RequestContext(object):
def __init__(self, app, environ):
self.app = app
self.url_adapter = app.url_map.bind_to_environ(environ)
self.request = app.request_class(environ)
self.session = app.open_session(self.request)
self.g = _RequestGlobals()
self.flashes = None
def __enter__(self):
_request_ctx_stack.push(self)
def __exit__(self, exc_type, exc_value, tb):
if tb is None or not self.app.debug:
_request_ctx_stack.pop()
_request_ctx_stack = LocalStack()
def dispatch_request(self):
try:
endpoint, values = self.match_request()
return self.view_functions[endpoint](**values)
except HTTPException, e:
handler = self.error_handlers.get(e.code)
if handler is None:
return e
return handler(e)
except Exception, e:
handler = self.error_handlers.get(500)
if self.debug or handler is None:
raise
return handler(e)
查询视图函数view_functions获得响应的处理函数。如果异常则返回响应的异常处理函数。
至此,基本把hello_world调用过程分析完。可以看到flask只是做了WSGI app的封装。核心功能包括路由、模板、周边处理。关于模板和预处理、后处理相关代码后续分析。