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 發生錯誤時,得到更多細節有利於追朔錯誤。
若有任何問題與指教歡迎與我聯繫,若覺得我的內容不錯麻煩幫我隨便點個廣告,謝謝。