3分钟搞定企业级应用的HTTP状态码和异常的使用,让你的应用更专业

24 阅读5分钟

fHhMutq4W

你是否也曾经历过这样的深夜?

前端同事怒气冲冲地跑来质问:“你这个接口怎么又报错了?到底成功没有?!”

你盯着日志一脸茫然,只能回复:“我也不知道啊,你看下返回什么...”

其实,问题往往出在那些被你忽视的HTTP状态码上。 3分钟,带你用FastAPI告别这种低级沟通困境。

HTTP 状态码:API 的通用语言

状态码是什么?

想象一下,向服务员点餐,他将给你一个简短的回应码,用来代表不同的情况:

200:表示 菜品已收到,马上为您制作

201:表示 新菜品已加入菜单,创建成功

404:表示 您点的菜品不存在

500:表示 厨房设备故障,无法制作

HTTP 状态码就是这样一套国际标准,让客户端能准确的理解服务端的处理结果。

常用的状态码分类

2xx - 成功响应(请求已成功处理)  
3xx - 重定向(需要进一步操作)
4xx - 客户端错误(请求包含错误)
5xx - 服务端错误(服务器处理失败)

核心状态码实战详解

首先,使用 from starlette import status 导入 status

现在,我们要做的是,明确的指定每个成功的 API 请求将返回的响应状态码。

2xx系列:成功响应

200 OK,是一个成功状态的标准响应,表示请求成功了。通常用于成功的获取请求数据,返回给客户端时。

@app.get("/books", status_code=status.HTTP_200_OK)
async def read_all_books():
    return BOOKS  # 获取数据成功,返回书籍列表

201 Created - 意味着请求成功,并创建资源成功了。在提交请求,为应用程序创建新实体对象时,经常使用。

@app.post("/create_book", status_code=status.HTTP_201_CREATED)
async def create_book(book_reqeust: BodyRequest):
    new_book = Book(**book_reqeust.model_dump())
    BOOKS.append(find_book_id(new_book))

204 No Content - 请求成功了,但没有内容返回。

@app.put("/books/update_book", status_code=status.HTTP_204_NO_CONTENT)
async def update_book(book: BodyRequest):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book.id:
            BOOKS[i] = book
4xx系列:客户端错误

404 Not Found - 意味着客户端请求的资源不存在。

@app.get("/books/{book_id}")
async def read_book(book_id: int = Path(gt=0)):
    for book in BOOKS:
        if book.id == book_id:
            return book
    raise HTTPException(status_code=404, detail="Item not found.")

422 Unprocessable Entity - 请求参数验证失败

# 当传入的book_id为0或负数时,FastAPI将自动返回422错误
@app.get("/books/{book_id}")
async def read_book(book_id: int = Path(gt=0)):
    # 业务逻辑...
5xx系列:服务端错误

500 Internal Server Error - 服务器内部错误,意味着服务器端 Python 代码在某个地方崩溃了。

# 当代码出现未处理的异常时,FastAPI自动返回500错误
@app.get("/books/{book_id}")
async def read_book(book_id: int):
    # 如果这里出现未处理的异常,返回500
    return BOOKS[book_id]  # 例如:索引越界,将触发500错误

HTTP异常处理:精准控制错误响应

自定义异常抛出

当业务逻辑需要主动抛出错误时,使用HTTPException

from fastapi import HTTPException

@app.put("/books/update_book")
async def update_book(book: BodyRequest):
    book_changed = False
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book.id:
            BOOKS[i] = book
            book_changed = True
            break
    
    if not book_changed:
        raise HTTPException(
            status_code=404,
            detail="Item not found"  # 书籍不存在,主动抛出404
        )

删除操作中的异常处理

@app.delete("/books/{book_id}")
async def delete_book(book_id: int = Path(gt=0)):
    book_changed = False
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book_id:
            BOOKS.pop(i)
            book_changed = True
            break
    
    if not book_changed:
        raise HTTPException(
            status_code=404,
            detail="Book not found"
        )

显式状态码响应:提升API专业性

为什么要显式指定状态码?

默认情况下,FastAPI会对成功请求返回200状态码。但通过显式指定,我们可以:

  1. 提高代码可读性:明确表达接口的意图
  2. 遵循RESTful规范:不同的操作返回最合适的状码
  3. 改善API文档:生成的文档会显示精确的状态码信息

状态码使用效果

前端开发者的体验提升

// 前端调用时,可以根据状态码进行精准处理
try {
    const response = await fetch('/api/books/123');
    
    if (response.status === 200) {
        // 处理成功数据
        const book = await response.json();
    } else if (response.status === 404) {
        // 处理资源不存在
        showErrorMessage('书籍不存在');
    } else if (response.status === 500) {
        // 处理服务器错误
        showErrorMessage('服务器异常,请稍后重试');
    }
} catch (error) {
    // 网络错误处理
}

最佳实践

核心要点

  1. 一致性:在整个API中保持状态码使用的一致性
  2. 准确性:为不同的操作结果返回最精确的状态码
  3. 可读性:通过显式指定状态码提高代码可读性
  4. 文档化:利用状态码改善API文档质量

实用建议

  1. 常见场景下,状态码选择
    • 获取数据成功:200 OK
    • 创建资源成功:201 Created
    • 更新/删除成功:200 OK(返回数据)或204 No Content(不返回数据)
    • 资源不存在:404 Not Found
    • 参数验证失败:422 Unprocessable Entity
  2. 错误信息设计
    • 提供清晰的错误描述
    • 避免泄露敏感信息
    • 保持错误格式的一致性

下节预告

下一期我们将探讨在 FastAPI 应用程序中如何添加数据库的设置?

欢迎 “关注”,我们在下一期一起来解锁这个问题。


-------- 写在最后 --------

关注我,每天1分钟,轻松懂 Python

我的同名公众号正在连载《FastAPI 开发实战》、《Python 核心技术》、《职场》。


点赞 :支持技术分享!

分享 :分享给身边感兴趣的朋友!

关注我 :获取更多FastAPI实战技巧!


#Python #FastAPI #API #Web开发 #程序员 #编程教程 #效率提升 #后端开发 #API设计 #参数验证