flask如何優雅的處理異常
如果使用flask編寫RESTful風格的程式,不可避免的就是異常的處理問題。flask預設的異常處理方式實在不敢恭維,如果想達到能友好的返回錯誤資訊,自己還要多做不少工作。
什麼算優雅的返回錯誤資訊呢?舉個例子,下面的程式碼是獲取User token的一段程式碼,如果密碼驗證失敗將會向前端反饋錯誤資訊,而反饋是通過丟擲異常:
def get_user_token(self, data): valid(get_token, data) with get_session() as session: if "username" in data: user = session.query(User).filter_by(user_name=data['username']).first() elif "email" in data: user = session.query(User).filter_by(email=data['email']).first() else: user = None if not user or not user.valid_passwd(data['password']): raise APIException("get_token_error", "can't get the token with a wrong user password", 400) expiration = data['expiration'] if "expiration" in data else 86400 return { "token": user.generate_auth_token(expiration=expiration), "id": user.id, }
那麼可以在上層邏輯捕獲這個異常,並把異常的資訊包裝一下優雅的反饋給前端,比如這樣處理:
try:
get_user_token(data)
except APIExcepting as e:
return json.dumps({
"id": e.error_id,
"message": e.message,
"code": e.code,
})
當然,這只是最簡單的包裝,而且是http狀態碼寫在了response的body裡,而最好應該直接返回相應狀態碼的response。
每個下層邏輯的異常由上層來處理是很常規的辦法,但是有的異常是可以直接拋到最上層的,比如引數錯誤,密碼錯誤等,這些異常差的只是一個友好的顯示,如果有辦法對這些異常自動封裝一個友好的反饋顯示,那麼就省不少事情。
而利用flask是可以實現這一點的,flask有一個叫errorhandler的東西,它可以捕捉特定的異常,然後根據這個異常進行自定義操作。那麼,我們就可以建立一個可以直接拋到最上層的異常,由errorhandler監聽捕捉這個異常,把捕捉到的異常封裝成友好的response反饋出去就可以了。
首先是寫一個可以被拋到最上層的異常:
class APIException(Base): def __init__(self, error_id, message, code=500): super(Base, self).__init__() self.raw_message = message self.error_id = error_id self.code = code self.message = message def to_dict(self): result = { "id": self.error_id, "code": self.code, "message": self.message, } return result
這個異常使用起來也很簡單raise APIException(error_id, message, status_code)
就可以了,而to_dict方法可以構建一個符合REST風格的錯誤資訊返回body。下面就差一個錯誤處理控制代碼來把APIEception的例項封裝成友好的response了。
@app.errorhandler(APIException)
def handle_api_exception(error):
from flask import jsonify
response = jsonify(error.to_dict())
response.status_code = error.code
return response
這樣就有了一個處理APIException的控制代碼,當有這個異常丟擲的話,它便會返回一個友好的body,而且狀態碼也會是在raise時制定的狀態碼。
歡迎到微信裡去當吃瓜群眾