

【个人主页:】
大语言模型(LLM)开发工程师|中国传媒大学·数字媒体技术(智能交互与游戏设计) 深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调 技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️ 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案 专栏传送门:LLM大模型开发 项目实战指南、Python 从真零基础到纯文本 LLM 全栈实战、从零学 SQL + 大模型应用落地、大模型开发小白专属:从 0 入门 Linux&Shell 「让AI交互更智能,让技术落地更高效」 欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!
你是不是写 FastAPI 接口时,遇到查询用户不存在只会返回默认的 HTML,或者直接抛 Internal Server Error?这篇详解 HTTP 状态码的分类、含义、FastAPI 的 4 种请求异常处理方式,配合学生管理系统的代码示例和对比表格,帮你优雅地处理各种异常场景。
在 API 接口开发的入门阶段,很多开发者会忽略 HTTP 状态码和请求异常处理,比如查询用户不存在时返回 200+{data:null},或者遇到数据库连接失败时直接抛出默认的 500 Internal Server Error。这种做法会导致以下问题:
因此,我们需要重视 HTTP 状态码和请求异常处理,优雅地处理各种异常场景。
HTTP 状态码是服务器对客户端请求的响应状态的数字代码。HTTP 状态码由三个数字组成,分为以下几类:
以下是 FastAPI 开发中最常用的 HTTP 状态码:
状态码 | 类型 | 含义 | 常见场景 |
|---|---|---|---|
200 | 成功 | OK | 请求已成功处理,返回请求的数据 |
201 | 成功 | Created | 请求已成功处理,创建了新的资源 |
400 | 客户端错误 | Bad Request | 请求参数有错误,如缺少必填参数、参数类型错误、参数格式错误 |
401 | 客户端错误 | Unauthorized | 用户未登录或登录状态已过期 |
403 | 客户端错误 | Forbidden | 用户已登录,但无权限访问该资源 |
404 | 客户端错误 | Not Found | 请求的资源不存在 |
500 | 服务器错误 | Internal Server Error | 服务器在处理请求时出现错误,如数据库连接失败、代码逻辑错误 |
503 | 服务器错误 | Service Unavailable | 服务器暂时不可用,如服务器正在维护、服务器负载过高 |
FastAPI 提供了 4 种请求异常处理方式:
语法:
from fastapi import HTTPException, status
def function_name():
...
if condition:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="请求的资源不存在")
...代码示例(学生管理系统):
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.models.students import Student
from app.schemas.students import StudentInfo
router = APIRouter(prefix="/students", tags=["Students"])
@router.get("/{student_id}", response_model=StudentInfo)
def get_student_info(student_id: int = 101, db: Session = Depends(get_db)):
"""获取单个学生信息"""
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="学生不存在")
return student测试:打开浏览器,访问 http://127.0.0.1:8000/docs,点击/students/{student_id}接口旁边的Try it out按钮,输入100,点击Execute,返回以下 JSON 响应:
{"detail":"学生不存在"}除了使用 FastAPI 内置的 status 模块,我们还可以直接使用数字作为 status_code 参数。
代码示例(学生管理系统):
@router.get("/{student_id}", response_model=StudentInfo)
def get_student_info(student_id: int = 101, db: Session = Depends(get_db)):
"""获取单个学生信息"""
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise HTTPException(status_code=404, detail="学生不存在")
return student测试:结果与方式一相同。
如果我们需要处理的异常场景比较复杂,可以创建自定义异常类继承 HTTPException。
代码示例(学生管理系统):
from fastapi import HTTPException, status
class StudentNotFoundException(HTTPException):
"""学生不存在异常"""
def __init__(self, student_id: int):
detail = f"学生ID为{student_id}的学生不存在"
super().__init__(status_code=status.HTTP_404_NOT_FOUND, detail=detail)
class StudentAlreadyExistsException(HTTPException):
"""学生已存在异常"""
def __init__(self, student_no: str):
detail = f"学号为{student_no}的学生已存在"
super().__init__(status_code=status.HTTP_400_BAD_REQUEST, detail=detail)在 API 接口中使用自定义异常类:
from app.schemas.students import StudentCreate
from app.services.students_service import create_student, get_student_by_no
from app.utils.exceptions import StudentAlreadyExistsException, StudentNotFoundException
@router.post("/", response_model=StudentInfo)
def create_student_info(student: StudentCreate, db: Session = Depends(get_db)):
"""创建学生信息"""
existing_student = get_student_by_no(db, student.student_no)
if existing_student:
raise StudentAlreadyExistsException(student.student_no)
new_student = create_student(db, student)
return new_student
@router.get("/{student_id}", response_model=StudentInfo)
def get_student_info(student_id: int = 101, db: Session = Depends(get_db)):
"""获取单个学生信息"""
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise StudentNotFoundException(student_id)
return student测试:打开浏览器,访问 http://127.0.0.1:8000/docs,点击/students接口旁边的Try it out按钮,输入以下 JSON 数据:
{
"student_no": "20250001",
"name": "张三",
"gender": "男",
"birthdate": "2005-01-01",
"phone": "13800138001",
"email": "zhangsan@example.com",
"address": "北京市海淀区"
}点击Execute,返回以下 JSON 响应:
{"detail":"学号为20250001的学生已存在"}如果我们需要处理全局的异常场景,可以使用 @app.exception_handler 装饰器捕获并处理异常。
代码示例(学生管理系统):
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from app.utils.exceptions import StudentNotFoundException, StudentAlreadyExistsException
app = FastAPI(title="学生管理系统", version="1.0.0", description="一个基于FastAPI的学生管理系统")
@app.exception_handler(StudentNotFoundException)
async def student_not_found_exception_handler(request: Request, exc: StudentNotFoundException):
"""学生不存在异常的全局处理函数"""
return JSONResponse(
status_code=exc.status_code,
content={
"code": exc.status_code,
"message": exc.detail,
"path": request.url.path
}
)
@app.exception_handler(StudentAlreadyExistsException)
async def student_already_exists_exception_handler(request: Request, exc: StudentAlreadyExistsException):
"""学生已存在异常的全局处理函数"""
return JSONResponse(
status_code=exc.status_code,
content={
"code": exc.status_code,
"message": exc.detail,
"path": request.url.path
}
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
"""全局异常处理函数"""
return JSONResponse(
status_code=500,
content={
"code": 500,
"message": "服务器内部错误",
"path": request.url.path,
"error": str(exc)
}
)测试:打开浏览器,访问 http://127.0.0.1:8000/docs,点击/students/{student_id}接口旁边的Try it out按钮,输入100,点击Execute,返回以下 JSON 响应:
{"code":404,"message":"学生ID为100的学生不存在","path":"/students/100"}代码示例:
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.models.users import User
from app.schemas.users import UserInfo
from app.utils.exceptions import UserNotFoundException
router = APIRouter(prefix="/users", tags=["Users"])
@router.get("/{user_id}", response_model=UserInfo)
def get_user_info(user_id: int, db: Session = Depends(get_db)):
"""获取单个用户信息"""
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise UserNotFoundException(user_id)
return user代码示例:
from app.schemas.users import UserCreate
from app.services.users_service import create_user, get_user_by_username
from app.utils.exceptions import UserAlreadyExistsException
@router.post("/", response_model=UserInfo)
def create_user_info(user: UserCreate, db: Session = Depends(get_db)):
"""创建用户信息"""
existing_user = get_user_by_username(db, user.username)
if existing_user:
raise UserAlreadyExistsException(user.username)
new_user = create_user(db, user)
return new_user代码示例:
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.security import authenticate_user, create_access_token
from app.schemas.auth import Token
from app.utils.exceptions import InvalidCredentialsException
router = APIRouter(prefix="/auth", tags=["Auth"])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
@router.post("/login", response_model=Token)
def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
"""用户登录"""
user = authenticate_user(db, form_data.username, form_data.password)
if not user:
raise InvalidCredentialsException()
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}代码示例:
from app.core.dependencies import get_current_active_admin_user
@router.get("/", response_model=list[UserInfo])
def get_users_info(page: int = 1, page_size: int = 10, db: Session = Depends(get_db), current_user: User = Depends(get_current_active_admin_user)):
"""获取用户列表(需要管理员权限)"""
# 查询用户列表的代码
return []代码示例:
from app.utils.exceptions import DatabaseConnectionException
@app.get("/")
def test_database_connection(db: Session = Depends(get_db)):
"""测试数据库连接"""
try:
# 执行一个简单的查询
db.execute("SELECT 1")
return {"message": "数据库连接成功"}
except Exception as e:
raise DatabaseConnectionException(str(e))问题:使用错误的 HTTP 状态码,如查询用户不存在时返回 400 而不是 404。
解决方案:根据 HTTP 状态码的分类和含义,选择合适的 HTTP 状态码。
问题:错误信息不详细,如只返回 “请求失败” 而不是 “学生 ID 为 100 的学生不存在”。
解决方案:在 HTTPException 或自定义异常类的 detail 参数中添加详细的错误信息。
问题:全局异常处理覆盖范围不完整,如没有处理特定的异常类。
解决方案:添加更多的 @app.exception_handler 装饰器,处理特定的异常类。
问题:全局异常处理时泄露服务器的敏感信息,如数据库连接失败时返回完整的错误堆栈。
解决方案:在生产环境中,不要在全局异常处理中返回完整的错误堆栈,只返回简单的错误信息。
通过以上步骤,我们详解了 HTTP 状态码的分类、含义、FastAPI 的 4 种请求异常处理方式,配合学生管理系统的代码示例和对比表格,帮你优雅地处理各种异常场景。
未来,我们可以对 FastAPI 的请求异常处理进行以下优化: