Flask 是一個 Python 實現的 Web 開發微框架, 有豐富的生態資源。本文從一段官方的示例代碼經過一步步打斷點方式解釋 Flask 內部的運行機制,在一些關鍵概念會有相關解釋,這些前提概念對總體理解 Flask框架十分重要,本文基於flask 0.1 版本進行相應的分析。html
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
複製代碼
第一行import Flask 類對象,這個無需解釋。跳到第二行,使用當前模塊的名字傳入Flask類中,並實例化Flask對象,咱們在這個地方打個斷點,看看Flask類別裏有什麼。 python
class Flask(object):
# 省略了註釋部分
# flask 用做請求對象的類
request_class = Request
# flask 用做響應對象的類
response_class = Response
# 靜態文件路徑
static_path = '/static'
# 密鑰,用於加密 session 或其它涉及安全的東西
secret_key = None
#存儲session對象數據的cookie名稱
session_cookie_name = 'session'
# Jinja2環境的一些選項
jinja_options = dict(
autoescape=True,
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
複製代碼
這部分是初始化Flask類中默認設置的一些屬性,其實經過名字也能夠大概知道每一個屬性的做用。看到這個地方時是否是一臉懵逼,Request、Response 是什麼東西,有什麼做用?Jinja2 又是什麼東西? 別急,下面慢慢解釋這幾個東西的做用。git
from werkzeug import Request as RequestBase, Response as ResponseBase
class Request(RequestBase):
"""The request object used by default in flask. Remembers the matched endpoint and view arguments. It is what ends up as :class:`~flask.request`. If you want to replace the request object used you can subclass this and set :attr:`~flask.Flask.request_class` to your subclass. """
def __init__(self, environ):
RequestBase.__init__(self, environ)
self.endpoint = None # 請求對象的端點
self.view_args = None # 請求視圖函數的參數
class Response(ResponseBase):
"""The response object that is used by default in flask. Works like the response object from Werkzeug but is set to have a HTML mimetype by default. Quite often you don't have to create this object yourself because :meth:`~flask.Flask.make_response` will take care of that for you. If you want to replace the response object used you can subclass this and set :attr:`~flask.Flask.request_class` to your subclass. """
default_mimetype = 'text/html'
複製代碼
經過源碼的註釋咱們能夠知道,Request、Response都只是對 werkzeug 庫的Request、Response 進行了一層包裝並加入一些屬性。先說一下它們的做用:github
看完上面源碼和解釋,是否是有新的疑問了,werkzeug又是什麼?端點又是什麼概念?額,werkzeug的做用真的很大,整個框架都是基於它實現的,下面會有一個部分專門說明這個庫。說明: werkzeug 庫和 jinja2 是 flask 的兩個依賴庫,會分出一篇文章專門介紹,這篇文章重點是整個 Flask 內部的機制,建議看到對應部分,先提早去讀兩個依賴庫的文章。正則表達式
接下來繼續下一步的調試,初始化一個Flask類, 先看看 Flask 類的初始化函數:數據庫
def _get_package_path(name):
"""Returns the path to a package or cwd if that cannot be found."""
# 獲取 模塊包 路徑,被 Flask 引用
try:
return os.path.abspath(os.path.dirname(sys.modules[name].__file__))
except (KeyError, AttributeError):
return os.getcwd()
class Flask(object):
# 簡化版,已經去掉註釋,建議看源碼註釋加上這個理解
def __init__(self, package_name):
# 設置是否開啓調試模式,若開啓,會監視項目代碼變化,
# 開發服務器重載 Flask 應用
self.debug = False
# 包或模塊的名字,模塊的名稱將會因其做爲單獨應用啓動仍是做爲模塊導入而不一樣
# Flask 才知道到哪去找模板、靜態文件
self.package_name = package_name
# 根據 Flask 傳入的__name__, 找到項目的根路徑
self.root_path = _get_package_path(self.package_name)
# 已註冊的全部視圖函數的字典,字典的鍵是函數名稱,能夠用來生成URL(url_for函數)
# 字典的值是函數自己, 想要註冊視圖函數,可使用 route 裝飾器
self.view_functions = {}
# 全部已註冊錯誤處理程序的字典, 字典的鍵是一個整數類型(integer)的錯誤碼
# 字典的值是對應錯誤的函數,想要註冊錯誤handler, 可使用 errorhandler 裝飾器
self.error_handlers = {}
# 請求開始進入時,但還請求還沒調度前調用的函數列表,也就是預處理操做
# 可用於打開數據庫鏈接或獲取當前登陸用戶,使用 before_route 裝飾器註冊
self.before_request_funcs = []
# 請求結束時調用的函數列表,這些函數會被傳入當前響應對象並將其修改或替換它。
self.after_request_funcs = []
# 不帶參數調用的函數列表,用於填充模板上下文,每一個應該返回更新模板上下文的字典
# 默認的處理器用來注入session、request和g
self.template_context_processors = [_default_template_ctx_processor]
# 使用 werkzeug 的 routing.Map, 用於給應用增長一些URL規則,
# URL規則造成一個Map實例的過程當中會生成對應的正則表達式,能夠進行URL匹配
self.url_map = Map()
# 添加靜態文件的URL映射規則
# SharedDataMiddleware中間件用來爲程序添加處理靜態文件的能力
if self.static_path is not None:
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 # URL路徑和實際文件目錄(static文件夾)的映射
})
# Jinja2 環境,它經過jinja_options建立,加載器(loader)經過
self.jinja_env = Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
# 將url_for, get_flashed_message 做爲全局對象填充入模板上下文中,能夠在模板中調用它們
self.jinja_env.globals.update(
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
複製代碼
上面就是一個 Flask 實例化時所作的工做,其實就是保存了一下配置信息,設置了一下Jinja2 環境,並定義了一個URL 映射對象,用於映射URL 到函數之間的關係。flask
開篇主要講了初始化一個Flask對象,內部作了什麼工做,配置了一下信息,設置了一下Jinja2 環境,定義了一些視圖函數存放的數據結構,定義了一個Map對象用於後面保存URL 和 視圖函數的映射關係。接下來會有更多關於werkzeug, jinja2 和 WSGI 相關文章放出來,敬請期待!!!安全
flask文檔服務器
flask項目源碼0.1版本cookie