Example of error handling in flask. (Part II).
在本範例你會學到:
- 簡易的 Flask API 架設 (上篇)
- 使用 Flask lib 的
abort
控制錯誤訊息 (下篇) - 使用
traceback
、sys
套件追蹤自己想要的訊息 (下篇)
在本範例你需要先準備好:
- 確認有安裝好
python3
環境(請捨棄python2
) - 安裝
flask
,本文使用flask==1.0.2
- 有個簡易的
terminal
或是jupyter
環境 - 抱著輕鬆學習的心
4.正常的錯誤訊息
接續前一篇的的範例,若還不知道如何建立 flask api 的朋友可以先看這篇
Flask 系列 - Flask error handling 教學(ㄧ)
以下就用簡單的例子噴錯給大家看,故意在程式裡面要取得清單不存在的 C
的長度
from flask import Flask, request, abort
app = Flask(__name__)
@app.route('/error_test_500',methods=['POST'])
def error_test_500():
post = request.json[0]
return len(post.get('C'))
if __name__ == '__main__':
app.run(host='0.0.0.0',port=1234, debug=False)
在 terminal 執行打入水果清單:
curl -d '[{"A": "apple","B": "banana"}]' -H "Content-Type: application/json" -X POST http://0.0.0.0:1234/error_test_500
將會乾淨利落的得到 500 Internal Server Error
而你的 terminal 會得到正確的錯誤訊息: TypeError: object of type 'NoneType' has no len()
5.為錯誤訊息加油添醋
上面的範例噴錯的問題在實際應用 api 很常見,在 docker
或 VM
環境中我們無法用debug
模式盯著,也不能隨便的 access 主機,後端人員突然跟你說噴錯又只拿到500 或 400 根本不知道是哪裡錯誤。
這時候主事者還要先問前端做了什麼操作來重現情境、再去問後端到底打了什麼給 API,基本上就是用經驗在猜測可能哪裡出錯。
所以 API
所帶出來的錯誤訊息就相當的重要,好的訊息可以大幅壓縮找蟲的時間啊,以下就教大家用比較簡單的方式獲取錯誤訊。
接下來壓軸出場的就是traceback
、sys
了,看字面意思其實也蠻好懂的,他們可以追朔所有的系統錯誤訊息,包含 行數
、class
、錯誤歷經的所有function
、錯誤訊息
等等的資訊,相當實用。
先放上完整範例再來一步一步解釋:
from flask import Flask, request, abort
import traceback
import sys
def abort_msg(e):
"""500 bad request for exception
Returns:
500 and msg which caused problems
"""
error_class = e.__class__.__name__ # 引發錯誤的 class
detail = e.args[0] # 得到詳細的訊息
cl, exc, tb = sys.exc_info() # 得到錯誤的完整資訊 Call Stack
lastCallStack = traceback.extract_tb(tb)[-1] # 取得最後一行的錯誤訊息
fileName = lastCallStack[0] # 錯誤的檔案位置名稱
lineNum = lastCallStack[1] # 錯誤行數
funcName = lastCallStack[2] # function 名稱
# generate the error message
errMsg = "Exception raise in file: {}, line {}, in {}: [{}] {}. Please contact the member who is the person in charge of project!".format(fileName, lineNum, funcName, error_class, detail)
# return 500 code
abort(500, errMsg)
app = Flask(__name__)
@app.route('/error_test_500',methods=['POST'])
def error_test_500():
post = request.json[0]
try:
return len(post.get('C'))
except Exception as e:
abort_msg(e)
if __name__ == '__main__':
app.run(host='0.0.0.0',port=1234, debug=False)
基本上主程式是相同的,故意 call 一個不存在的len(post.get('C'))
讓他錯誤,但是這次加上了try,except
,當他噴500時,就執行 abort_msg(e)
處理錯誤的 function。
這個 abort_msg
基本上做了兩件事情:
- 利用
traceback
、sys
將錯誤資訊完整的抓出來組成字串 - 利用 flask 的
abort
方法主動拋出 500錯誤並附加上而外的字串訊息,而不是讓 python自己噴錯,直接看結果圖:
是不是發現結果不是單純的 500 錯誤了呢!,這次還加上了錯誤的位置、行數、型態、原因
等等,甚至還可以加上聯絡人的資訊,是不是相當的一目了然呢!
參考資料
以上為下篇的內容,簡易的分享如何在 API 發生錯誤時,得到更多細節有利於追朔錯誤。
若有任何問題與指教歡迎與我聯繫,若覺得我的內容不錯麻煩幫我隨便點個廣告,謝謝。