這個系列是學習《Flask Web開發(fā):基于Python的Web應用開發(fā)實戰(zhàn)》的部分筆記
客戶端——web 服務器——WSGI——application
客戶端發(fā)送 HTTP 請求,web 服務器在一個地址的端口上等待接收抵碟,一旦收到仪缸,會將請求通過 WSGI 交給 application 處理逸月,application 就是 flask 框架編寫的應用可帽,application 對消息處理后,也通過 WSGI 返回 HTTP 響應給 web 服務器装哆,由服務器發(fā)送給客戶端台颠。
所有 Flask 程序都必須創(chuàng)建一個程序實例,實例是 Flask 類的對象
安裝
$ pip install flask
Collecting flask
Collecting itsdangerous>=0.21 (from flask)
Collecting Werkzeug>=0.7 (from flask)
Using cached Werkzeug-0.11.2-py2.py3-none-any.whl
Collecting Jinja2>=2.4 (from flask)
Using cached Jinja2-2.8-py2.py3-none-any.whl
Collecting MarkupSafe (from Jinja2>=2.4->flask)
Installing collected packages: itsdangerous, Werkzeug, MarkupSafe, Jinja2, flask
Successfully installed Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.2 flask-0.10.1 itsdangerous-0.24
創(chuàng)建實例:
run.py
from flask import Flask
app = Flask(__name__)
Flask 函數(shù)需要指定一個參數(shù)裸影,是程序主模塊或包的名字挣轨,大多數(shù)情況下,__name__
就是需要的值轩猩。
Flask 用這個參數(shù)決定程序的根目錄,以便稍后能夠找到相對于程序根目錄的資源文件卷扮。
web 服務器
常見的有 uWSGI、Nginx均践、gunicorn 等
flask 集成了一個開發(fā)用的web服務器晤锹,同一時間只能處理一個請求
使用 flask 集成的服務器
run.py
if __name__ == '__main__':
app.run(debug=True)
debug = True, 調試模式,激活調試器彤委,當一些文件修改保存后鞭铆,會自動重新加載,而且出錯時焦影,能夠顯示足夠的提示信息车遂,具體到運行哪個文件的哪一行產生的錯誤,錯誤原因是什么斯辰。正因為會提供豐富的后臺信息舶担,所以強烈建議不要在生產環(huán)境中開啟。
運行
$ python run.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
WSGI
web 服務器和 web 框架 有很多種椒涯,并不總是能互相配合工作柄沮,那就要想辦法在它們之間搭建一個溝通的橋梁回梧,讓它們能正撤掀瘢互發(fā)消息,于是出現(xiàn)了 WSGI 規(guī)范狱意,規(guī)定了 web 服務器將客戶端的消息發(fā)送給 application 湖苞,以及 application 將處理后的消息發(fā)送給服務器的方法,這個規(guī)范在PEP 333中定義详囤。
flask 對消息的處理
上下文
在多線程服務器中财骨,定義了一個線程池,由多個線程同時處理不同客戶的不同請求(并發(fā))藏姐,當收到請求后隆箩,會選一個線程進行處理。flask 使用 程序/請求 上下文羔杨,臨時把某些對象在一個線程中設置為“全局可訪”捌臊,這樣既不會干擾其他線程,又使得所有視圖都能夠訪問這些對象兜材,并處理請求理澎。flask 收到請求后逞力,在將請求交給線程之前,會 激活/推送 上下文糠爬,建立環(huán)境寇荧,上下文的內容來自 web 服務器 通過 WSGI 發(fā)給 application 的消息,當請求處理完成后执隧,再刪除上下文揩抡。
在 Flask 中有兩種上下文: 程序上下文 和 請求上下文 全局變量
| 變量名 | 上下文說明 |
|---|---|---|
| current_app | 當前激活程序的程序實例 |
| g | 處理請求時用作臨時存儲的對象。每次請求都會重置這個變量 |
| request | 請求對象,封裝了客戶端發(fā)出的 HTTP 請求中的內容 |
| session | 用戶會話,用于存儲請求之間需要“記住”的值的詞典 |
路由殴玛、視圖函數(shù)
- URL 映射
創(chuàng)建視圖時捅膘,會將 URL、HTTP 方法 和特定的視圖進行綁定滚粟,建立URL 映射
run.py
@app.route('/') # 使用程序實例提供的`app.route`修飾器,把函數(shù)與URL綁定
def index():
return '<h1>Hello World!</h1>'
用瀏覽器訪問http://localhost:5000/
查看URL 映射
>>> from run import app
>>> app.url_map
Map([<Rule '/' (HEAD, POST, OPTIONS, GET) -> index>,
<Rule '/user/<username>' (HEAD, OPTIONS, GET) -> main.user>])
>>>
GET寻仗、POST 是請求方法,由路由進行處理凡壤。Flask 為每個路由都指 定了請求方法,這樣不同的請求方法發(fā)送到相同的 URL 上時,會使用不同的視圖函數(shù)進 行處理署尤。HEAD 和 OPTIONS 由 Flask 自動處理。
當線程收到 HTTP 請求后亚侠,在URL映射
中尋找相應 URL曹体、HTTP方法 對應的視圖,由該視圖進行處理硝烂,并返回響應給 web 服務器箕别,發(fā)送給客戶端。
某些 URL 格式,會發(fā)現(xiàn)很多地址中都包含可變部分滞谢,F(xiàn)lask 支持這種形式的 URL,只需在 route 修飾器中使用特殊的句法即可
- 關鍵字參數(shù)
http://localhost:5000/user/john
@app.route('/user/<name>') # 對 url 中串稀,/user/ 后面的內容進行匹配、截取狮杨,賦值給變量 name母截,默認匹配字符串,可以指定類型橄教。例如清寇,/user/<int:id> 只匹配 id 為整數(shù)的 URL
def user(name): # 變量 name 作為參數(shù)傳遞給函數(shù) user
print name
- 額外參數(shù)
作為 查詢字符串(url 中問號后面的),這個參數(shù)可從 request.args 字典中讀取
http://127.0.0.1:5000/index?page=2
@app.route('/index')
def index():
page = request.args.get('page', 1, type=int)
print request.args
ImmutableMultiDict([('page', u'2')])
page=request.args.get('page', 1, type=int)
從 url 獲取 鍵為 page 的 值轉換為整形护蝶,如果沒有 或 轉換失敗华烟,默認為 1
鉤子
在將請求交給視圖處理前,或將視圖處理的結果返回給 web 服務器前持灰,可以調用鉤子盔夜,對 請求/響應 進行處理。例如,對于一個用戶的請求比吭,檢查這個用戶的賬號有沒有通過郵箱確認绽族,如果沒有,對某些頁面的訪問會被禁止訪問衩藤,重定向到一個特定的頁面吧慢,而其他頁面正常訪問。
請求鉤子使用修飾器實現(xiàn)赏表。Flask 支持以下 4 種鉤子:
- before_first_request:注冊一個函數(shù),在處理第一個請求之前運行检诗。
- before_request:注冊一個函數(shù),在每次請求之前運行。
- after_request:注冊一個函數(shù),如果沒有未處理的異常拋出,在每次請求之后運行瓢剿。
- teardown_request:注冊一個函數(shù),即使有未處理的異常拋出,也在每次請求之后運行逢慌。
響應
Flask 調用視圖函數(shù)后,會將其返回值作為響應的內容。大多數(shù)情況下,響應就是一個簡單的字符串,作為 HTML 頁面(也就是 HTTP 的 body)回送客戶端间狂。
- 元組
但 HTTP 協(xié)議需要的不僅是作為請求響應的字符串攻泼。HTTP 響應中一個很重要的部分是狀態(tài)碼
,Flask 默認設為 200,這個代碼表明請求已經(jīng)被成功處理。如果視圖函數(shù)返回的響應需要使用不同的狀態(tài)碼,那么可以把數(shù)字代碼
作為第二個返回值,添加到響應文本之后鉴象。
@app.route('/')
def index():
return '<h1>Bad Request</h1>', 400
視圖函數(shù)返回的響應還可接受第三個參數(shù),這是一個由首部(header)組成的字典
,可以 添加到 HTTP 響應中忙菠。
- Response 對象
如果不想返回由 1 個、2 個或 3 個值組成的元組,Flask 視圖函數(shù)還可以使用 make_response() 產生并直接返回完整的Response 對象
纺弊。make_response() 函數(shù)可以接受 1 個牛欢、2 個或 3 個參數(shù)(和視圖函數(shù)的返回值一樣),并返回一個Response 對象
。有時我們需要在視圖函數(shù)中產生Response 對象
,然后在Response 對象
上調用各種方法,進一步 設置響應 淆游。
from flask import make_response
@app.route('/')
def index():
response = make_response('<h1>This document carries a cookie!</h1>')
response.set_cookie('answer', '42') # 設置 cookie
return response
- 重定向
有一種名為重定向
的特殊響應類型傍睹。這種響應沒有頁面文檔, 只是用于告訴瀏覽器一個新地址,以便加載新頁面犹菱。重定向經(jīng)常在 Web 表單中使用拾稳。
重定向經(jīng)常使用 302 狀態(tài)碼表示,指向的地址由 HTTP 的Location 首部
提供。重定向響應可以使用 3 個值形式的返回值生成,也可在 Response 對象中設定已亥。不過,由于使用頻繁,Flask 提供了redirect() 輔助函數(shù)
, 用于生成這種響應熊赖。
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.example.com')
- 異常跳出
還有一種特殊的響應由abort 函數(shù)
生成,用于處理錯誤来屠。
from flask import abort
@app.route('/user/<id>')
def get_user(id):
user = load_user(id)
if not user: # 如果用戶不存在
abort(404) # 拋出異常
return '<h1>Hello, %s</h1>' % user.name
注意,abort 會直接跳出調用它的函數(shù)虑椎,拋出異常,把控制權交給 Web 服務器俱笛。
flask 的組件
被設計為可擴展形式捆姜,只自帶兩個核心組件:
- werkzeug,負責處理 路由迎膜、調試泥技、WSGI
- jinja2,模板引擎磕仅,負責對模板進行渲染
其他組件需要單獨安裝珊豹、初始化
擴展的來源:
- 社區(qū)開發(fā)
- py 標準庫/包
- 自行開發(fā)
使用:
pip install flask-mail
# pip 安裝
from flask.ext.mail import Mail
# 導入, 專為 Flask 開發(fā)的擴展簸呈,都在 flask.ext 命名空間下, virtualenv 環(huán)境中,目錄為lib/python2.7/site-packages/
mail = Mail(app)
# 初始化店茶,將 程序實例(app) 作為參數(shù)傳給 擴展的構造函數(shù)蜕便,進行初始化。通常在創(chuàng)建程序實例時進行贩幻。
mail.send(msg)
# 使用