請求鈎子:
當我們需要對請求進行預處理和后處理時,就可以用Flask提供的回調函數(鈎子),他們可用來注冊在請求處理的不同階段執行的處理函數。這些請求鈎子使用裝飾器實現,通過程序實例app調用,以 before_request鈎子為例(請求之前),當你對一個函數附加了app.before_request裝飾器后,就會將這個函數注冊為before_request處理函數,每次執行請求前都會觸發所有before_request函數
Flask默認 實現的五種鈎子:
示例代碼:
定義了三個視圖函數 A,B,C,其中C使用了after_this_request鈎子,在網頁中請求url 為/C,會觸發C視圖函數,在執行該函數的流程是先進入before_first_requst鈎子,然后進入before_request鈎子,之后進入C函數內部注冊的after_this_request鈎子函數。
之后的after_requet和teardown_request在觸發響應條件時會執行。
@app.before_request
def before_request():
print "before request"
@app.before_first_request
def before_first_request():
print "before first request"
# @app.after_request
# def after_request(response):
# print "after request"
@app.after_request
def per_request_callbacks(response):
for func in getattr(g, 'call_after_request', ()):
print "after request"
response = func(response)
return response
@app.route('/A')
def A():
return '<p> this is function A</p>'
@app.route('/B')
def B():
return '<p>this is function B</p>'
@app.route('/C')
def C():
@flask.after_this_request
def after_this_request(response):
print "after this request"
#raise ValueError
return response
return "<p>after this request</p>"
if __name__ == '__main__':
app.run(debug = True)
結果:
http響應
Flask程序中,客戶端的請求會觸發相應的視圖函數,獲取返回值作為響應的主題,最后生成完整的響應,即響應報文
響應報文:
響應報文有協議版本、狀態碼、原因短語、響應首部和響應主體組成
響應報文的首部包含一些關於響應和服務器的信息,這些內容有Flask生成,而我們在視圖函數中返回的內容即為響應報文中的主體內容。瀏覽器接收響應后,會把返回的響應主題解析並顯示 在瀏覽器窗口上。
HTTP狀態碼用來表示請求處理的結果
在Flask中生成響應
響應在Flask中使用Response對象表示 ,響應報文中的大部分內容有服務器處理,大多數情況下,我們只負責返主題內容。
Flask處理請求時會先判斷是否可以找到與請求URL相匹配的路由,如果沒有則返回404響應。如果有,則調用對應的視圖函數,視圖函數的返回值構成了響應報文的主題內容,正確返回時狀態碼默認為200,Flask會調用make_response()方法將視圖函數返回值轉換為響應對象。
完整的說,視圖函數可以返回最多有三個元素組成的元祖:響應主題、狀態碼、首部字段。其中首部字段可以為字典,或是兩元素元祖組成的列表([(‘Location’,’http://localhost:5000/hi’),(‘contentType’,’…’)])
flask請求成功時默認的響應碼是200
可以對請求指定不同的響應狀態碼:指定url為hi的請求的響應狀態碼為201
結果:
重定向
重定向可以通過修改30X響應的首部Location的字段的值來進行:
在視圖函數中,return語句后面用字典的形式指定Location的值,訪問的時候,會根據Location的值進行重定向
@app.route('/redirect')
def redirect():
return "<p>This is a redirect pare</p>"
@app.route('/hello1')
def hello1():
print "redirect..."
return '', 302, {'Location': 'http://127.0.0.1:5000/redirect'}
if __name__ == '__main__':
app.run(debug = True)
結果:
訪問hello1路徑時,頁面進行了重定向,重定向的位置是首部中Location字段的URL
也可以通過Flask提供的redirect()函數來生成重定向響應
from flask import Flask,redirect
@app.route('/hello2')
def hello2():
return redirect('http://localhost:5000/redirect')
if __name__ == '__main__':
app.run(debug = True)
結果:
修改重定向redirect函數返回碼為303
@app.route('/hello2')
def hello2():
return redirect('http://localhost:5000/redirect',303)
if __name__ == '__main__':
app.run(debug = True)
結果:
程序內重定向到其他視圖函數
如果要在程序內重定向到其他視圖函數,可以在redirect()函數中使用url_for()函數生成目標URL,可以在響應首部的Location看到重定向的目標URL,重定向到其他視圖其實就是重定向到該視圖對應的url
from flask import Flask,redirect,url_for
@app.route('/hello3')
def hello3():
return redirect(url_for('redirect'))#重定向到/redirect
@app.route('/redirect')
def redirect():
return "<p>This is a redirect pare</p>"
if __name__ == '__main__':
app.run(debug = True)
結果:
手動返回錯誤響應
大多數情況下,Flask會自動處理常見的錯誤響應。HTTP錯誤對應的異常類在Werkzeug的werkzeug.exceptions模塊中定義,拋出這些異常即可返回對應的錯誤響應。如果你想手動返回錯誤響應,可以使用Flask提供的abort()函數。
在abort()函數中傳入狀態碼即可返回對應的錯誤響應。
需要注意,abourt()函數被調用后,abort()函數之后的代碼不會被執行。
例子為手動返回404錯誤:
from flask import abort
@app.route('/404')
def not_found():
abort(404)
if __name__ == '__main__':
app.run(debug = True)
結果:
響應格式:
在http響應中,數據可以通過多種格式傳輸,我們會使用HTML格式,這也是Flask中的默認審核制。在特定的情況下,我們也會用其他格式。不同的響應數據格式需要設置不同的MIME類型,MIME類型在首部的Content-Type字段中定義,以默認的HTML類型為例 :
Content-Type: text/html; charset=utf-8
MIME類型
MIME類型(又稱media type或content type)是一種用來表示文件類型的機制,它與文件擴展名相對應,可以讓客戶端區分不同的內容類型,並執行不同的操作。一般的格式為“類型名/子類型名”。其中子類型名一般為文件擴展名。比如HTML的MIME類型為”text/html”,png圖片的MIME類型為”image/png”。
如果想使用其他MIME類型,可以通過Flask提供的make_response()方法生成響應對象,傳入響應的主體作為參數,然后使用響應對象的mimetype屬性設置MIME類型,不需要設置字符集(charset)選項。
修改MIME類型:
from flask import make_response
@app.route('/foo')
def foo():
response = make_response('Hello,World!')
response.mimetype = 'text/plain'
return response
結果:
常用的數據格式(純文本、HTML、XML和JSON)對應的MIME類型
純文本的MIME類型:text/plain
HTML的MIME類型:text/html
XML的MIME類型:application/xml
JSON的MIME類型:application/json
Flask提供JSON的支持
Flask通過引入Python標准庫中的json模塊為程序提供了JSON支持。你可以直接從Flask中導入json對象,然后調用dumps()方法將字典、列表或元祖序列化為JSON字符串,在使用前面介紹的方法修改MIME類型,即可返回JSON響應
例如:
用json模塊把響應轉換為JSON
from flask import Flask,make_response,json
@app.route('/foo1')
def foo1():
data={'name':'Sam Xia','gender':'male'}
response = make_response(json.dumps(data))
response.mimetype = 'application/json'
return response
if __name__ == '__main__':
app.run(debug = True)
結果:
也可以jsonnify()方法轉換響應內容為JSON
不過我們一般並不直接使用json模塊的dumps()、load()等方法,因為Flask通過包裝這些方法提供了更方便的jsonify()函數。用jsonify()函數,我們進需要傳入數據或參數,他會把傳入的參數轉化成JSON字符串作為響應的主體,然后生成一個響應對象,並且設置正確的MIME類型。
例如:
@app.route('/foo3')
def foo3():
return jsonify(name = 'Sam Xia',gender = 'make')
if __name__ == '__main__':
app.run(debug = True)
結果:
jsonify()函數可以接收多種形式的參數。可以傳入如上邊的關鍵字參數,也可以像dumps()方法一樣傳入字段、列表或元祖,如:
from flask import jsonify
@app.route('/foo3')
def foo3():
return jsonify({'name':'Sam Xia','gender' : 'make'})#傳入字典
if __name__ == '__main__':
app.run(debug = True)
結果:
jsonify()函數可以自定義響應碼
from flask import jsonify
@app.route('/foo3')
def foo3():
return jsonify(message = 'Error !'),500
if __name__ == '__main__':
app.run(debug = True)
結果: