前言
通常我們可以通過 raise 拋出一個 HTTPException
異常,請求參數(shù)不合法會拋出RequestValidationError
異常,這是最常見的2種異常。
HTTPException 異常
向客戶端返回 HTTP 錯誤響應(yīng),可以使用?raise
觸發(fā)?HTTPException
。
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/path/{name}")
async def read_unicorn(name: str):
if name == "yoyo":
raise HTTPException(404, detail=f"name: {name} not found")
return {"path_name": name}
默認(rèn)情況下返回json格式
HTTP/1.1 404 Not Found
date: Wed, 27 Sep 2023 02:07:07 GMT
server: uvicorn
content-length: 22
content-type: application/json
{"detail":"Not Found"}
覆蓋默認(rèn)的HTTPException 異常
查看HTTPException
異常相關(guān)源碼
from starlette.exceptions import HTTPException as StarletteHTTPException
class HTTPException(StarletteHTTPException):
def __init__(
self,
status_code: int,
detail: Any = None,
headers: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(status_code=status_code, detail=detail, headers=headers)
HTTPException 異常是繼承的 starlette 包里面的 HTTPException
覆蓋默認(rèn)異常處理器時需要導(dǎo)入?from starlette.exceptions import HTTPException as StarletteHTTPException
,并用?@app.excption_handler(StarletteHTTPException)
?裝飾異常處理器。
from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException
from fastapi.responses import PlainTextResponse, JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
# # 捕獲 HTTPException 異常
@app.exception_handler(StarletteHTTPException)
def http_error(request, exc):
print(exc.status_code)
print(exc.detail)
# return JSONResponse({'error_msg': exc.detail}, status_code=exc.status_code)
return PlainTextResponse(content=exc.detail, status_code=exc.status_code)
@app.get("/path/{name}")
async def read_unicorn(name: str):
if name == "yoyo":
raise HTTPException(404, detail=f"name: {name} not found")
return {"path_name": name}
這樣原來的 HTTPException 返回 json 格式,現(xiàn)在改成返回text/plain
文本格式了。
HTTP/1.1 404 Not Found
date: Wed, 27 Sep 2023 07:24:58 GMT
server: uvicorn
content-length: 20
content-type: text/plain; charset=utf-8
name: yoyo not found
覆蓋請求驗證異常
請求中包含無效數(shù)據(jù)時,FastAPI?內(nèi)部會觸發(fā)?RequestValidationError
。
該異常也內(nèi)置了默認(rèn)異常處理器。
覆蓋默認(rèn)異常處理器時需要導(dǎo)入?RequestValidationError
,并用?@app.excption_handler(RequestValidationError)
?裝飾異常處理器。
這樣,異常處理器就可以接收?Request
?與異常。
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return PlainTextResponse(str(exc), status_code=400)
@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}
訪問?/items/foo
,可以看到以下內(nèi)容替換了默認(rèn) JSON 錯誤信息:
{
"detail": [
{
"loc": [
"path",
"item_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
以下是文本格式的錯誤信息:
HTTP/1.1 400 Bad Request
date: Wed, 27 Sep 2023 07:30:38 GMT
server: uvicorn
content-length: 103
content-type: text/plain; charset=utf-8
1 validation error for Request
path -> item_id
value is not a valid integer (type=type_error.integer)
RequestValidationError 源碼分析
RequestValidationError 相關(guān)源碼
class RequestValidationError(ValidationError):
def __init__(self, errors: Sequence[ErrorList], *, body: Any = None) -> None:
self.body = body
super().__init__(errors, RequestErrorModel)
使用示例
from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
print(exc.json())
print(exc.errors())
print(exc.body) # 請求body
return JSONResponse(
status_code=400,
content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
)
class Item(BaseModel):
title: str
size: int
@app.post("/items/")
async def create_item(item: Item):
return item
現(xiàn)在試著發(fā)送一個無效的?item
,例如:
{
"title": "towel",
"size": "XL"
}
運行結(jié)果
HTTP/1.1 400 Bad Request
date: Wed, 27 Sep 2023 07:51:36 GMT
server: uvicorn
content-length: 138
content-type: application/json
{"detail":[{"loc":["body","size"],"msg":"value is not a valid integer","type":"type_error.integer"}],"body":{"title":"towel","size":"XL"}}
RequestValidationError
?和?ValidationError
如果您覺得現(xiàn)在還用不到以下技術(shù)細(xì)節(jié),可以先跳過下面的內(nèi)容。
RequestValidationError
?是 Pydantic 的?ValidationError
的子類。
FastAPI?調(diào)用的就是?RequestValidationError
?類,因此,如果在?response_model
?中使用 Pydantic 模型,且數(shù)據(jù)有錯誤時,在日志中就會看到這個錯誤。
但客戶端或用戶看不到這個錯誤。反之,客戶端接收到的是 HTTP 狀態(tài)碼為?500
?的「內(nèi)部服務(wù)器錯誤」。
這是因為在_響應(yīng)_或代碼(不是在客戶端的請求里)中出現(xiàn)的 Pydantic?ValidationError
?是代碼的 bug。文章來源:http://www.zghlxwxcb.cn/news/detail-727778.html
修復(fù)錯誤時,客戶端或用戶不能訪問錯誤的內(nèi)部信息,否則會造成安全隱患。文章來源地址http://www.zghlxwxcb.cn/news/detail-727778.html
到了這里,關(guān)于FastAPI學(xué)習(xí)-23.異常處理器 exception_handler的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!