介绍
业务规则不满足,产生的错误,代码本身没有崩溃,程序可以正常继续运行,是业务逻辑层面的不符合预期。
例子
- 用户账号密码错误
- 余额不足,不能下单
- 订单状态已取消,不能重复取消
- 权限不足,禁止访问该数据
- 手机号已经被注册
- 商品库存为 0,无法购买
特点
- 不是程序 bug,属于正常业务场景;
- 服务没有崩溃,可以正常返回给前端提示;
- HTTP 状态码一般仍然用 200 OK,在返回体内部用自定义code表示错误;
- 不需要打印 ERROR 堆栈(大部分场景打 warn 即可)。
实现
继承 Exception,定义业务错误
例如业务码:
10001账号不存在10002密码错误
自定义业务异常
class BusinessException(Exception):
def __init__(self, code:int, msg:str):
self.code = code
self.msg = msg
注册处理器
捕获自定义业务异常
@app.exception_handler(BusinessException)
async def business_exception_handler(request: Request, exc: BusinessException):
return JSONResponse(
status_code=200, # 业务异常http码用200,靠内部code区分,前后端常用方案
content={
"code": exc.code,
"msg": exc.msg,
"data": None
}
)
实现视图函数
@app.get('/student/{name}')
async def get_student(name: str):
if name == '李雷':
ret = {
"code": 200,
"data": {
'name': '李雷',
'age': 21,
}}
else:
raise BusinessException(code=10001, msg="没有此学号的学生")
return ret
完整代码
from fastapi import FastAPI, Path
from fastapi.exceptions import RequestValidationError
from starlette.requests import Request
from starlette.responses import JSONResponse
app = FastAPI()
class BusinessException(Exception):
def __init__(self, code:int, msg:str):
self.code = code
self.msg = msg
@app.exception_handler(BusinessException)
async def business_exception_handler(request: Request, exc: BusinessException):
return JSONResponse(
status_code=200, # 业务异常http码用200,靠内部code区分,前后端常用方案
content={
"code": exc.code,
"msg": exc.msg,
# "data": None
}
)
@app.get('/student/{name}')
async def get_student(name: str):
if name == '李雷':
ret = {
"code": 200,
"data": {
'name': '李雷',
'age': 21,
}}
else:
raise BusinessException(code=10001, msg="没有此学号的学生")
return ret
测试成功
浏览器访问:http://127.0.0.1:8000/student/李雷 ,浏览器显示:
{
"code": 200,
"data": {
"name": "李雷",
"age": 21
}
}
测试找不到学生
浏览器访问:http://127.0.0.1:8000/student/lili ,浏览器显示:
{
"code": 10001,
"msg": "没有此学号的学生"
}