前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FastAPI--错误处理(5)

FastAPI--错误处理(5)

作者头像
py3study
发布2020-06-28 14:26:55
1.2K0
发布2020-06-28 14:26:55
举报
文章被收录于专栏:python3python3

一、概述

HTTPException异常抛出

再之前Bottle 中其实有一个就是HttpError异常类,在FastAPI也存在这么一个HTTPException。比如:

代码语言:javascript
复制
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

代码语言:javascript
复制
http://127.0.0.1:8000/items/asda
1.png
1.png

 我们查看HTTPException和StarletteHTTPException的源码发现他们也是继承与Exception:

代码语言:javascript
复制
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且返回新增自定义请求头

代码语言:javascript
复制
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

代码语言:javascript
复制
http://127.0.0.1:8000/items-header/asda
1.png
1.png

查看Headers,发现多了X-Error

1.png
1.png

自定义返回HTTPException

类似之前Bottle我们通过添加一个自定义的全局的错误,来统一的处理返回。FastAPI其实也提供一个自定义错误的机制:

官方示例如下:

代码语言:javascript
复制
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)

观察请求结果:

代码语言:javascript
复制
http://127.0.0.1:8000/unicorns/yolo
1.png
1.png

 当请求name == yolo的时候,我们主动抛出了UnicornException,而且我们,@app.exception_handler(UnicornException)也捕获到相关的异常信息,且返回了相关的信息。

覆盖FastAPI默认的异常处理

按官方文档说明就是,当请求包含无效的数据的时候,或参数提交异常错误的时候,会抛出RequestValidationError,

那其实我也可以通过上面的自定义异常的方式来覆盖重写我们的RequestValidationError所返回信息:

如: 默认代码没有添加覆盖处理的话: 发生异常的时候是提示是:

代码语言:javascript
复制
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)

发生异常的请求下返回:

代码语言:javascript
复制
http://127.0.0.1:8000/items/yolo
1.png
1.png

 恢复覆盖的时候:

代码语言:javascript
复制
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)

请求结果:

1.png
1.png

上面的返回其实我们还可以修改一下返回如下,指定响应码:

代码语言:javascript
复制
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)

再次请求一下

1.png
1.png

 可以发现状态码是指定的422,返回信息也是指定的。

本文参考链接:

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、概述
    • HTTPException异常抛出
      • HTTPException且返回新增自定义请求头
        • 自定义返回HTTPException
          • 覆盖FastAPI默认的异常处理
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档