You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:44:53