因為0.1版本整體代碼大概只有350行,比較簡單。所以本篇文章會以Flask 0.1版本源碼為基礎進行剖析Flask應用的啟動過程。
Flask參考資料flask,官網有一個最簡單app:
from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080,debug=True)
下面就以上面這個最簡單的Flask app為起點,以v0.1版本源碼為核心進行說明整個Flask應用的啟動過程:
一、初始化App
from flask import Flask #導入Flask類 app = Flask(__name__) #1、實例化Flask app
flask.py文件:
1.1、定義類變量
class Flask(object):
'''
全局變量
'''
request_class = Request
response_class = Response
static_path = '/static'
secret_key = None
session_cookie_name = 'session'
jinja_options = dict(
autoescape=True,
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
a、request_class變量是一個Request類,Request類繼承自werkzeug的Request類。它調用了werkzeug的Request類的構造函數,RequestBase.__init__(self, environ)。然后又初始化了endpoint和view_args兩個變量。
b、response_class變量是一個Response類。繼承自werkzeug的Reponse類。且自己初始化了變量default_mimetype=‘text/html’。
c、static_path是靜態文件路徑,默認值為/static。
d、secret_key默認值為None。關於secret_key的作用,用官方的語言來解釋:
If a secret key is set, cryptographic components can use this to sign cookies and other things. Set this to a complex random value when you want to use the secure cookie for instance. 如果設置了secret_key,加密組件使用這個key簽名cookies。當你要使用安全cookie,你要把這個key設置成復雜的隨機值。 This attribute can also be configured from the config with the SECRET_KEY configuration key. Defaults to None. 這個屬性可以通過在配置文件中設置SECRET_KEY來設置。默值為None。
e、session_cookie_name,session的名字為session。
f、jinja_options選項初始化。
1.2、初始化構造函數
def __init__(self, package_name):
self.debug = False #debug變量為False
self.package_name = package_name #一般為__name__,如果以本模塊運行,則為__main__;如果是被調用,則為app文件名。
self.root_path = _get_package_path(self.package_name) #獲取app的絕對路徑
self.view_functions = {} #視圖函數
self.error_handlers = {} #錯誤處理
self.before_request_funcs = [] #HTTP請求之前需要執行的函數
self.after_request_funcs = [] #HTTP請求結束之后,需要執行的函數
self.template_context_processors = [_default_template_ctx_processor] #上下文模板變量:session、g、request
self.url_map = Map() #url集合
if self.static_path is not None: #self.static_path默認值為'/static',所以默認會把它加入到url_map集合中。Map([<Rule '/static/<filename>' -> static>])
self.url_map.add(Rule(self.static_path + '/<filename>',
build_only=True, endpoint='static'))
if pkg_resources is not None:
target = (self.package_name, 'static')
else:
target = os.path.join(self.root_path, 'static')
self.wsgi_app = SharedDataMiddleware(self.wsgi_app, {
self.static_path: target
})
self.jinja_env = Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
self.jinja_env.globals.update(
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
在構造函數中,主要定義了一些變量(debug、包名、包路徑、視圖函數、上下文相關、路由、static路徑、模板相關環境)
二、路由處理
@app.route('/hello')
def hello_world():
return 'Hello World!'
flask.py文件
2.1 定義路由裝飾器
功能就是完成url_map和view_functions的初始化,其中Rule是werkzeug提供的工具。
def route(self, rule, **options): #route裝飾器,裝飾路由的同時,把路由添加進Map,添加視圖函數,確保路由和視圖函數映射起來
def decorator(f):
self.add_url_rule(rule, f.__name__, **options) #Map([<Rule '/hello'(HEAD,GET) -> hello_world>])
self.view_functions[f.__name__] = f #view_functions = {'hello_world':hello_world}
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))
三、app.run()
前面兩個步驟,都是初始化操作,為后續啟動做准備。包括初始化環境變量和路由添加。
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080,debug=True)
app正式啟動了。過程如下:
flask.run()
--> werkzeug.run_simple()
--> werkzeug.inner()
--> werkzeug.serving.make_server()
-->serve_forever()
-->SocketServer.BaseServer.HTTPServer.serve_forever() #While True:****
至此,一個flask的app已經跑起來了。
