Flask 系列 - Flask error handling 教學(二)

Example of error handling in flask. (Part II).

在本範例你會學到:

  • 簡易的 Flask API 架設 (上篇)
  • 使用 Flask lib 的 abort 控制錯誤訊息 (下篇)
  • 使用 tracebacksys 套件追蹤自己想要的訊息 (下篇)

在本範例你需要先準備好:

  • 確認有安裝好 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

500 Internal Server Error

而你的 terminal 會得到正確的錯誤訊息: TypeError: object of type 'NoneType' has no len()

5.為錯誤訊息加油添醋

上面的範例噴錯的問題在實際應用 api 很常見,在 dockerVM 環境中我們無法用debug模式盯著,也不能隨便的 access 主機,後端人員突然跟你說噴錯又只拿到500 或 400 根本不知道是哪裡錯誤。

這時候主事者還要先問前端做了什麼操作來重現情境、再去問後端到底打了什麼給 API,基本上就是用經驗在猜測可能哪裡出錯。

所以 API 所帶出來的錯誤訊息就相當的重要,好的訊息可以大幅壓縮找蟲的時間啊,以下就教大家用比較簡單的方式獲取錯誤訊。

接下來壓軸出場的就是tracebacksys了,看字面意思其實也蠻好懂的,他們可以追朔所有的系統錯誤訊息,包含 行數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 基本上做了兩件事情:

  • 利用tracebacksys將錯誤資訊完整的抓出來組成字串
  • 利用 flask 的 abort 方法主動拋出 500錯誤並附加上而外的字串訊息,而不是讓 python自己噴錯,直接看結果圖:

500 Internal Server Error

是不是發現結果不是單純的 500 錯誤了呢!,這次還加上了錯誤的位置、行數、型態、原因等等,甚至還可以加上聯絡人的資訊,是不是相當的一目了然呢!

參考資料

以上為下篇的內容,簡易的分享如何在 API 發生錯誤時,得到更多細節有利於追朔錯誤。

https://flask-restplus.readthedocs.io/en/stable/errors.html

https://dotblogs.com.tw/caubekimo/2018/09/17/145733

若有任何問題與指教歡迎與我聯繫,若覺得我的內容不錯麻煩幫我隨便點個廣告,謝謝。


 上一篇
Github - 如何刪除GitHub上所有的 commit(一) Github - 如何刪除GitHub上所有的 commit(一)
How to remove all history commit and push again?大家應該都有一個經驗,在程式或是網頁的檔案都準備就緒,repository 也創好之後,快樂的下了 git push 指令上去 Github,按
2020-03-18
下一篇 
Flask 系列 - Flask error handling 教學(ㄧ) Flask 系列 - Flask error handling 教學(ㄧ)
Example of error handling in flask. (Part I).在本範例你會學到: 簡易的 Flask API 架設 (上篇) -> 如果已經熟悉 flask 可直接跳下篇 使用 Flask lib 的 a
2020-02-19
  目錄