Flask框架——應用錯誤處理

上篇文章我們學習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等相關文章!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末礁苗,一起剝皮案震驚了整個濱河市爬凑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌试伙,老刑警劉巖嘁信,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疏叨,居然都是意外死亡潘靖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門蚤蔓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卦溢,“玉大人,你說我怎么就攤上這事〉ゼ牛” “怎么了贬芥?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宣决。 經(jīng)常有香客問我蘸劈,道長,這世上最難降的妖魔是什么疲扎? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任昵时,我火速辦了婚禮,結果婚禮上椒丧,老公的妹妹穿的比我還像新娘壹甥。我一直安慰自己,他們只是感情好壶熏,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布句柠。 她就那樣靜靜地躺著,像睡著了一般棒假。 火紅的嫁衣襯著肌膚如雪溯职。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天帽哑,我揣著相機與錄音谜酒,去河邊找鬼。 笑死妻枕,一個胖子當著我的面吹牛僻族,可吹牛的內容都是我干的。 我是一名探鬼主播屡谐,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼述么,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了愕掏?” 一聲冷哼從身側響起度秘,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饵撑,沒想到半個月后剑梳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡肄梨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年阻荒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片众羡。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡侨赡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情羊壹,我是刑警寧澤蓖宦,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站油猫,受9級特大地震影響稠茂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜情妖,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一睬关、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毡证,春花似錦电爹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恤煞,卻和暖如春屎勘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背居扒。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工概漱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喜喂。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓犀概,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夜惭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內容