FastAPI入口路径移除中间件单元测试404失败求助
FastAPI入口路径移除中间件单元测试404失败求助
看起来你遇到的核心问题是测试时中间件没有被正确注册,导致请求路径没被修改,最终匹配不到/test端点返回404。我帮你拆解问题原因并给出完整的修复方案:
问题根源分析
你的api.py中,FastAPI app和中间件是在模块加载阶段就初始化完成的——当测试模块import api时,环境变量INGRESS_PATH_TO_REMOVE_FROM_INCOMING_REQUESTS还没被fixture设置,所以ingress_path是空字符串,中间件根本没被注册到app上。后续fixture里设置环境变量已经晚了,app的中间件列表不会再更新。
另外,当前中间件的路径替换逻辑用了全局replace,存在误替换风险(比如路径中其他位置出现相同字符串会被错误移除),也需要优化。
修复步骤
1. 重构API代码:动态创建App
把App的创建改成可配置的函数,避免模块加载时的静态初始化,让中间件可以根据参数动态注册:
# api.py import os import logging from fastapi import FastAPI, Request def create_app(ingress_path: str = "") -> FastAPI: app = FastAPI( title="title", description="description", version="1.0.0", contact={"name": "Me"}, ) # 中间件逻辑移到函数内,根据传入的ingress_path注册 if ingress_path: @app.middleware("http") async def modify_request_response_middleware(request: Request, call_next): # 优化:只替换开头匹配的ingress路径,避免误替换 if request.url.path.startswith(ingress_path): logging.debug( f"Removing ingress path '{ingress_path}' from the Request URL: '{request.url.path}'" ) # 截取ingress_path之后的部分,确保只替换开头 new_path = request.url.path[len(ingress_path):] # 处理替换后路径为空的情况(比如原路径就是ingress_path本身) if not new_path: new_path = "/" logging.debug(f"Modified URL: '{new_path}'") request.scope["path"] = new_path response = await call_next(request) return response # 这里可以添加你的其他路由、依赖等 return app # 生产环境下从环境变量读取配置创建App ingress_path = os.getenv( "INGRESS_PATH_TO_REMOVE_FROM_INCOMING_REQUESTS", "", ) app = create_app(ingress_path)
2. 修正测试代码:动态创建带中间件的App
现在测试可以直接调用create_app函数传入指定的ingress路径,不需要依赖环境变量,也能确保中间件被正确注册:
# test_api.py import pytest from fastapi.testclient import TestClient from api import create_app @pytest.fixture def app_with_ingress_path(mock_dependencies): """Create FastAPI app with ingress path middleware enabled""" return create_app(ingress_path="/api/v1") def test_middleware_removes_ingress_path_from_url(app_with_ingress_path): """Test that middleware removes ingress path from request URL""" # 给测试用的App添加测试端点 @app_with_ingress_path.get("/test") async def test_endpoint(): return {"message": "test"} client = TestClient(app_with_ingress_path) # 发送带ingress前缀的请求 response = client.get("/api/v1/test") # 验证响应状态码和内容 assert response.status_code == 200 assert response.json() == {"message": "test"}
3. 额外优化:验证中间件的路径修改逻辑
如果想确认中间件确实修改了路径,可以在测试中添加日志断言,或者用caplog捕获日志输出:
def test_middleware_modifies_request_path(app_with_ingress_path, caplog): caplog.set_level("DEBUG") @app_with_ingress_path.get("/test") async def test_endpoint(): return {"message": "test"} client = TestClient(app_with_ingress_path) client.get("/api/v1/test") # 验证日志输出(确认路径被正确修改) assert f"Removing ingress path '/api/v1' from the Request URL: '/api/v1/test'" in caplog.text assert f"Modified URL: '/test'" in caplog.text
这样修改后,测试就能正确触发中间件,把/api/v1/test转换成/test,匹配到端点后返回200,彻底解决404的问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

