FastAPI--錯誤處理(5)


一、概述

HTTPException異常拋出

再之前Bottle 中其實有一個就是HttpError異常類,在FastAPI也存在這么一個HTTPException。比如:

import uvicorn
from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}

@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

在上面的代碼中,通過判斷item_id是不是存在於items來主動的拋出了一個404的錯誤

 

 訪問一個錯誤的url

http://127.0.0.1:8000/items/asda

 

 我們查看HTTPException和StarletteHTTPException的源碼發現他們也是繼承與Exception:

class HTTPException(StarletteHTTPException):
    def __init__(
        self, status_code: int, detail: Any = None, headers: dict = None
    ) -> None:
        super().__init__(status_code=status_code, detail=detail)
        self.headers = headers

所以我們對於異常通常可以直接的使用 raise來拋出異常。

 

HTTPException且返回新增自定義請求頭

import uvicorn
from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}

@app.get("/items-header/{item_id}")
async def read_item_header(item_id: str):
    if item_id not in items:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error": "There goes my error"},
        )
    return {"item": items[item_id]}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

訪問一個錯誤的url

http://127.0.0.1:8000/items-header/asda

查看Headers,發現多了X-Error

 

自定義返回HTTPException

類似之前Bottle我們通過添加一個自定義的全局的錯誤,來統一的處理返回。FastAPI其實也提供一個自定義錯誤的機制:

官方示例如下:

import uvicorn
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name

app = FastAPI()

@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )

@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
    if name == "yolo":
        raise UnicornException(name=name)
    return {"unicorn_name": name}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

觀察請求結果:

http://127.0.0.1:8000/unicorns/yolo

 

 當請求name == yolo的時候,我們主動拋出了UnicornException,而且我們,@app.exception_handler(UnicornException)也捕獲到相關的異常信息,且返回了相關的信息。

 

覆蓋FastAPI默認的異常處理

按官方文檔說明就是,當請求包含無效的數據的時候,或參數提交異常錯誤的時候,會拋出RequestValidationError,

那其實我也可以通過上面的自定義異常的方式來覆蓋重寫我們的RequestValidationError所返回信息:

如: 默認代碼沒有添加覆蓋處理的話: 發生異常的時候是提示是:

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

# @app.exception_handler(RequestValidationError)
# async def validation_exception_handler(request, exc):
#     return JSONResponse({'mes':'觸發了RequestValidationError錯誤,,錯誤信息:%s 你妹的錯了!'%(str(exc))})

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

發生異常的請求下返回:

http://127.0.0.1:8000/items/yolo

 

 恢復覆蓋的時候:

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

@app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): return JSONResponse({'mes':'觸發了RequestValidationError錯誤,,錯誤信息:%s 你妹的錯了!'%(str(exc))})

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

請求結果:

上面的返回其實我們還可以修改一下返回如下,指定響應碼:

 

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.responses import JSONResponse
from fastapi import FastAPI, Request,status
from fastapi.encoders import jsonable_encoder

app = FastAPI()

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
    )

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        # 注意fastapi包中的HTTPException才可以定義請求頭
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

再次請求一下

 可以發現狀態碼是指定的422,返回信息也是指定的。

 

本文參考鏈接:

http://www.zyiz.net/tech/detail-119883.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM