上篇文章我們學習Flask框架——基于類的視圖庐氮,這篇文章學習Flask框架——應用錯誤處理语稠。
即使我們的代碼是百分百正確,但是還是會時撑常看見出錯仙畦,這是因為和代碼相關聯(lián)的東西會出錯,例如:
- 客戶端中斷了請求音婶,但應用程序還在讀取數(shù)據(jù)慨畸;
- 數(shù)據(jù)庫已經(jīng)過載,無法處理查詢衣式;
- 文件系統(tǒng)沒有存儲空間寸士;
- 硬盤崩潰,后臺服務過載碴卧;
- 使用的庫出現(xiàn)程序錯誤弱卡;
- 服務器與另一個系統(tǒng)的網(wǎng)絡連接出錯;
除了這些錯誤還有很多錯誤住册,在生產(chǎn)環(huán)境下婶博,我們通過把出錯情況記錄到日志里面。但這不是最好的處理錯誤方式荧飞。接下來我們學習更好的出錯處理方式凡人。
錯誤日志工具
當web應用程序運行發(fā)生錯誤時名党,我們可以通過日志文件來找錯誤信息并處理錯誤,但只要有足夠多的用戶觸發(fā)了該錯誤或不同的錯誤挠轴,即使是很簡單的錯誤传睹,這樣通過日志文件來找錯誤信息并處理錯誤就會變得很困難。
這時我們可以使用Sentry來處理應用錯誤岸晦,Sentry可以統(tǒng)計重復錯誤欧啤、捕獲堆棧數(shù)據(jù)和本地變量用于排錯,并在發(fā)生新的錯誤時或按指定頻度發(fā)送電子郵件委煤。
在使用Sentry時堂油,執(zhí)行如下代碼安裝flask依賴的sentry-sdk客戶端:
pip install sentry-sdk[flask]
安裝成功后,我們需要dsn值碧绞,dsn可以通過以下方式獲取:
1吱窝、進入sentry注冊登錄網(wǎng)站注冊賬號讥邻,如下圖所示:
這些注冊信息可以隨意填寫,但Email和password需要我們記住院峡,用來登錄查看sentry發(fā)送的錯誤信息兴使。
2、創(chuàng)建項目照激,如下圖所示:
這里我們選擇了flask发魄,點擊創(chuàng)建項目就會跳轉到如下網(wǎng)頁:
我們通過官網(wǎng)提供的示例代碼來演示如何使用sentry,代碼如下所示:
from flask import Flask
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init( #初始化配置
dsn="YOUR_DSN_HERE", #設置dsn值
integrations=[FlaskIntegration()], #整合器
traces_sample_rate=1.0 #捕獲的性能數(shù)據(jù)量俩垃,值在0-1之間
)
app = Flask(__name__)
if __name__ == '__main__':
app.run()
首先導入sentry的庫和方法励幼,在進行sentry_sdk的初始化配置,接著編寫一個視圖函數(shù)口柳,代碼如下所示:
@app.route('/debug-sentry')
def trigger_error():
division_by_zero = 1 / 0
視圖函數(shù)的語法沒有問題苹粟,但由于0不能為被除數(shù),所以當我們訪問/debug-sentry的URL時跃闹,會觸發(fā)一個錯誤,這個錯誤信息會被sentry捕獲。
運行flask程序负间,并訪問http://127.0.0.1:5000/debug-sentry唯笙,如下圖所示:
該錯誤信息大概是說:服務器遇到內部錯誤,服務器過載或應用程序出錯找默。
登錄sentry后艇劫,如下圖所示:
這樣我們就成功捕獲了錯誤信息和出錯的次數(shù)了。
錯誤處理器
在Flask中發(fā)生錯誤時啡莉,會返回一個相應的HTTP狀態(tài)碼港准,狀態(tài)碼400499表示客戶端的請求數(shù)據(jù)或與之相關的錯誤旨剥,狀態(tài)碼500599表示服務器或應用本身的錯誤。
例如:在我們請求一個不存在的URL鏈接時浅缸,會發(fā)出一個404 Not Found錯誤轨帜,如下圖所示:
當發(fā)生錯誤時,向用戶顯示我們自定義的出錯頁面時衩椒,我們可以使用錯誤處理器蚌父。
錯誤處理器是一個函數(shù),類似視圖函數(shù)的函數(shù)毛萌,當發(fā)生某類錯誤時苟弛,返回一個傳遞了正在處理的錯誤的實例響應。
注冊錯誤處理器
在使用錯誤處理器時阁将,需要先注冊錯誤處理器膏秫,注冊錯誤處理器有兩種方法:使用errorhandler裝飾函數(shù)注冊、使用register_error_handler()來注冊 做盅,示例代碼如下:
#使用裝飾器函數(shù)注冊
@app.errorhandler(werkzeug.exceptions.BadRequest) #傳遞子類BadRequest
#@app.errorhandler(400) #或傳遞標準HTTP代碼
def handle_bad_request(e):
return '錯誤請求', 400 #返回出錯代碼400
#使用register_error_handler()注冊
def handle_bad_request(e):
return 'bad request!', 400 #返回出錯代碼400
app.register_error_handler(400, handle_bad_request)
在使用errorhandler裝飾器函數(shù)注冊時缤削,需要傳入werkzeug.exceptions.HTTPException的子類,例如BadRequest或者傳遞標準HTTP代碼吹榴,如400亭敢,在返回響應時需要設置出錯代碼。
自定義錯誤頁面
為了更能告訴用戶錯誤信息图筹,我們可以自定義錯誤頁面帅刀,首先注冊一個錯誤處理器器,再abort()函數(shù)远剩,該函數(shù)可以中止請求扣溺,產(chǎn)生HTTP錯誤。Flask程序示例代碼如下:
import werkzeug
from flask import Flask, abort
app=Flask(__name__)
@app.errorhandler(400)
def handle_bad_request(e):
return '錯誤請求', 400 #返回錯誤信息
@app.route('/')
def hello_world():
abort(400) #使用abort()函數(shù)民宿,傳遞400HTTP代碼
if __name__ == '__main__':
app.run()
啟動Flask程序娇妓,訪問http://127.0.0.1:5000/時,網(wǎng)頁會顯示錯誤請求活鹰。
除了上面返回錯誤信息的數(shù)據(jù)格式哈恰,我們可以將錯誤信息以JSON的格式來返回,示例代碼如下:
from flask import Flask, abort,jsonify
app=Flask(__name__)
@app.errorhandler(404) #注冊404錯誤處理器
def resource_not_found(e):
return jsonify(error=str(e)), 404 #使用jsonify()方法接收錯誤對象e志群,并傳入錯誤HTML代碼404
@app.route('/')
def hello_world():
abort(404,description="Resource not found") #拋出錯誤處理器錯誤信息
if __name__ == '__main__':
app.run(debug=True)
啟動Flask程序着绷,訪問http://127.0.0.1:5000/時,網(wǎng)頁會顯示如下內容:
{
"error": "404 Not Found: Resource not found"
}
自定義錯誤處理器HTTP代碼
注意:Werkzeug 無法識別非標準HTTP代碼锌云,當返回出錯代碼不是標準的HTTP代碼時荠医,會報錯,例如:返回出錯代碼1000
KeyError: "'1000' is not a recognized HTTP error code. Use a subclass of HTTPException with that code instead."
Werkzeug 無法識別非標準HTTP代碼,也就是使用上面的方法無法注冊非標準HTTP代碼的錯誤處理器彬向。
這時我們自定義一個HTTPException子類兼贡, 注冊并拋出異常類,F(xiàn)lask程序示例代碼如下:
import werkzeug
from flask import Flask, abort, render_template
app=Flask(__name__)
class InsufficientStorage(werkzeug.exceptions.HTTPException): #自定義HTTP錯誤子類
code=1000
description = 'Not enough storage space.'
def handle_1000(e):
return '服務器無法存儲完成請求所必須的內容',1000 #返回錯誤信息及HTTP代碼
app.register_error_handler(InsufficientStorage, handle_1000) #注冊錯誤處理器
@app.route('/')
def hello_world():
raise InsufficientStorage() #拋出錯誤處理器錯誤信息
if __name__ == '__main__':
app.run(debug=True)
這里我們創(chuàng)建了名為InsufficientStorage的子類娃胆,子類里面的內容可以是隨意的遍希,再創(chuàng)建一個名為handle_1000()的函數(shù),該函數(shù)返回錯誤請求和HTTP代碼里烦。最后使用register_error_handler()方法注冊錯誤處理器——InsufficientStorage子類和handle_507凿蒜。
啟動Flask程序,訪問http://127.0.0.1:5000/胁黑,如下圖所示:
通用錯誤處理器
通用錯誤處理器就是把HTTP出錯信息轉換為JSON并展示在網(wǎng)頁中废封,示例代碼如下所示:
import werkzeug
from flask import Flask, abort, render_template
from flask import json
from werkzeug.exceptions import HTTPException
app=Flask(__name__)
@app.errorhandler(HTTPException) #注冊錯誤處理器
def handle_exception(e): #錯誤處理器函數(shù)傳入錯誤對象e
response = e.get_response() #獲取錯誤響應
response.data = json.dumps({ #編輯錯誤響應內容
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json" #設置響應類型
return response
@app.route('/')
def hello_world():
abort(501) #使用abort()傳入501錯誤代碼
if __name__ == '__main__':
app.run(debug=True)
首先使用errorhandler裝飾器注冊錯誤處理器,并定義錯誤處理器函數(shù)接收錯誤對象e丧蘸,根據(jù)錯誤對象e來編輯返回錯誤響應內容漂洋。
啟動Flask程序,訪問http://127.0.0.1:5000/触趴,如下圖所示:
好了氮发,F(xiàn)lask框架——應用錯誤處理就學到這里了,感謝觀看冗懦,下篇文章我們繼續(xù)學習Flask框架——Bootstrap-Flask使用。
公眾號:白巧克力LIN
該公眾號發(fā)布Python仇祭、數(shù)據(jù)庫披蕉、Linux、Flask乌奇、自動化測試没讲、Git等相關文章!