这篇博客介绍了如何在 FastAPI 项目中实现全局的中间件和异常处理机制,以及如何进行部署优化。文章详细展示了如何在应用中集成跨域支持、请求处理时间统计等中间件,并通过自定义异常类和异常处理函数来增强错误管理。此外,介绍了如何在部署阶段配置 Gunicorn 服务器以确保服务的高效运行,最终实现一个健壮且易于扩展的 FastAPI 项目架构。
1.项目文件结构 这部分展示了 FastAPI 项目的文件夹结构,涵盖了项目的各个模块,包括 API 路由(api
)、数据访问层(dao
)、异常处理(exceptions
)、表单验证(forms
)、中间件(middlewares
)、数据库模型(model
)、工具类(utils
)等。清晰的目录结构帮助开发者快速理解项目的组织方式,确保模块化和可维护性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ├── api │ └── users.py ├── dao │ └── user_dao.py ├── exceptions │ ├── exception.py │ └── handle.py ├── forms │ └── user_form.py ├── middlewares │ ├── handle.py │ └── middleware.py ├── model │ ├── __init__.py │ └── user.py ├── utils │ ├── async_redis.py │ ├── depends.py │ └── response.py ├── main.py └── requirements.txt
2.main.py main.py
文件集成了自定义的异常处理和中间件。handle_exception
和 handle_middleware
分别负责处理全局的异常和中间件,提升了系统的可扩展性和错误响应的统一性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from contextlib import asynccontextmanagerfrom fastapi import FastAPIfrom api import usersfrom model import db_initfrom utils.async_redis import RedisUtilfrom exceptions.handle import handle_exceptionfrom middlewares.handle import handle_middleware@asynccontextmanager async def lifespan (app: FastAPI ): print ('服务启动...' ) await db_init() app.state.redis = await RedisUtil.create_redis_pool() yield print ('服务关闭...' ) app = FastAPI(lifespan=lifespan) app.include_router(users.users_router) handle_exception(app) handle_middleware(app)
3.中间件 middlewares/middleware.py middleware.py
中定义了两个常见的中间件:
跨域中间件 (CORS)允许指定的前端应用跨域访问 FastAPI 后端 API。通过设置 allow_origins
来限制允许的前端来源。
处理时间中间件 :用于计算每个请求的处理时间,并将其以 X-Process-Time
头部返回,帮助开发者了解每个请求的处理效率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import timefrom fastapi import FastAPI, Requestfrom fastapi.middleware.cors import CORSMiddlewaredef add_cors_middleware (app: FastAPI ): """ 添加跨域中间件 :param app: FastAPI对象 :return: """ origins = [ 'http://localhost:5000' , 'http://127.0.0.1:5000' , ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True , allow_methods=['*' ], allow_headers=['*' ], ) def add_process_time_middleware (app: FastAPI ): @app.middleware("http" ) async def add_process_time_header (request: Request, call_next ): start_time = time.time() response = await call_next(request) process_time = time.time() - start_time print ('处理时间:' , process_time) response.headers["X-Process-Time" ] = str (process_time) return response
middlewares/handle.py handle.py
是一个中间件处理的集中管理模块,调用了 add_cors_middleware
和 add_process_time_middleware
两个函数来注册中间件。这个文件的目的是使中间件的管理更加模块化和清晰。
1 2 3 4 5 6 7 8 9 10 11 12 from fastapi import FastAPIfrom middlewares.middleware import add_cors_middleware, add_process_time_middlewaredef handle_middleware (app: FastAPI ): """ 全局中间件处理 """ add_cors_middleware(app) add_process_time_middleware(app)
4.异常处理 exceptions/exception.py exception.py
文件定义了一个自定义的 LoginException
类,用于处理与登录相关的特定异常。这个异常类可以带有错误数据和详细的错误消息,帮助开发者更好地捕获和诊断特定的错误场景。
1 2 3 4 5 6 7 8 9 10 11 from typing import Optional class LoginException (Exception ): """ 自定义登录异常LoginException """ def __init__ (self, data: Optional [str ] = None , message: Optional [str ] = None ): self .data = data self .message = message
exceptions/handle.py handle.py
负责注册全局异常处理器。它处理了:
自定义的 LoginException
异常,返回特定的认证错误消息。
RequestValidationError
异常,捕获数据验证失败时的错误,并返回规范化的错误信息。
HTTPException
异常,处理 HTTP 错误并返回状态码和错误详情。
Exception
异常,捕获其他未知错误并返回通用的错误响应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from fastapi import FastAPI, Requestfrom fastapi.exceptions import HTTPException, RequestValidationErrorfrom exceptions.exception import LoginExceptionfrom utils.response import HttpResponsedef handle_exception (app: FastAPI ): """ 全局异常处理 """ @app.exception_handler(LoginException) async def auth_exception_handler (request: Request, exc: LoginException ): return HttpResponse.unauth_error(data={'login_error' : exc.data}, msg=exc.message) @app.exception_handler(RequestValidationError) async def validation_exception_handler (request: Request, exc: RequestValidationError ): return HttpResponse.params_error( data={ "error" : "Validation failed" , "details" : exc.errors(), "message" : "Invalid input data. Please correct the fields and try again." , }, ) @app.exception_handler(HTTPException) async def http_exception_handler (request: Request, exc: HTTPException ): return HttpResponse.server_error(data={'code' : exc.status_code, 'msg' : exc.detail}) @app.exception_handler(Exception) async def exception_handler (request: Request, exc: Exception ): return HttpResponse.server_error(msg=str (exc))
5.项目部署 在部署部分,文章介绍了如何使用 Gunicorn 启动 FastAPI 应用,并通过配置 -w
参数设置适当数量的 worker 进程,以便在生产环境中提高应用的处理能力。-w
参数的推荐值是根据系统的 CPU 核心数来确定的:CPU * 2 + 1
。此外,提供了测试命令和预期的错误响应,演示了如何通过中间件和异常处理机制返回详细的错误信息。
1 2 3 4 5 6 7 8 9 10 11 gunicorn main:app -b 127.0 .0 .1 :5000 -n my_app -w 4 -k uvicorn.workers.UvicornWorker curl -X GET 127.0 .0 .1 :5000 /api/v1/users_v1/0 客户端触发参数验证异常,包装后返回: {"code" :400 ,"msg" :"客户端参数错误" ,"data" :{"error" :"Validation failed" ,"details" :[{"type" :"greater_than_equal" ,"loc" :["path" ,"user_id" ],"msg" :"Input should be greater than or equal to 1" ,"input" :"0" ,"ctx" :{"ge" :1 }}],"message" :"Invalid input data. Please correct the fields and try again." },"state" :null} 服务端中间件打印: 处理时间: 0.0005788803100585938