FastAPI RedirectResponse在AWS部署重定向时返回Forbidden问题
使用FastAPI结合Docker、Serverless在AWS API Gateway部署API,所有路由通过请求头x-api-key完成鉴权保护。尝试用fastapi.responses.RedirectResponse实现/abc/item到/xyz/item的重定向:本地无鉴权校验时功能正常,部署到AWS后直接访问两个路由均能正常返回结果,但触发重定向时却返回{"message": "Forbidden"}。
已尝试传递status_code=status.HTTP_303_SEE_OTHER和status.HTTP_307_TEMPORARY_REDIRECT参数,问题未解决。通过curl调试发现响应头包含CloudFront相关信息,但CloudFront控制台无对应配置;CloudWatch日志显示重定向指令已执行,但最终返回Forbidden。
相关路由代码:
@router.get("/abc/item") async def get_item(item_id: int, request: Request, db: Session = Depends(get_db)): if False: redirect_url = f"/xyz/item?item_id={item_id}" logging.info(f"Redirecting to {redirect_url}") return RedirectResponse(redirect_url, headers=request.headers) else: execution = db.execute(text(items_query)) return convert_to_json(execution)
@router.get("/xyz/item") async def get_item(item_id: int, db: Session = Depends(get_db)): execution = db.execute(text(other_items_query)) return convert_to_json(execution)
serverless.yml路由配置:
events: - http: path: abc/item method: get cors: true private: true request: parameters: querystrings: item_id: true - http: path: xyz/item method: get cors: true private: true request: parameters: querystrings: item_id: true
额外信息:FastAPI添加了自定义中间件处理两个数据库连接(关联items和other_items表),该中间件在本地环境工作正常。
1. 修复请求头传递问题
直接传递完整request.headers时,AWS API Gateway可能过滤掉x-api-key这类敏感头,导致重定向后的请求缺失鉴权信息:
- 手动提取并仅传递
x-api-key头:redirect_headers = {"x-api-key": request.headers.get("x-api-key")} return RedirectResponse(redirect_url, headers=redirect_headers, status_code=status.HTTP_307_TEMPORARY_REDIRECT) - 注意:307状态码会保留原始请求方法和头信息,但仍需确认API Gateway的头传递规则是否允许
x-api-key通过。
2. 检查API Gateway与CloudFront的头转发规则
- 在API Gateway阶段配置中,将
x-api-key添加到"HTTP Headers"白名单,确保头信息能在路由间传递。 - 若使用CloudFront,检查缓存策略或行为设置,确认
x-api-key被包含在转发的头列表中(即使控制台无显式配置,也需验证默认规则是否移除了该头)。
3. 改用后端逻辑转发替代HTTP重定向
既然两个路由属于同一FastAPI应用,直接在后端调用目标路由的处理函数,完全绕过API Gateway的重定向鉴权限制:
@router.get("/abc/item") async def get_item(item_id: int, request: Request, db: Session = Depends(get_db)): if True: # 直接复用/xyz/item的业务逻辑 return await get_item_xyz(item_id, db) else: execution = db.execute(text(items_query)) return convert_to_json(execution) # 提取公共逻辑方便复用 async def get_item_xyz(item_id: int, db: Session): execution = db.execute(text(other_items_query)) return convert_to_json(execution) @router.get("/xyz/item") async def get_item(item_id: int, db: Session = Depends(get_db)): return await get_item_xyz(item_id, db)
这种方式不仅解决鉴权问题,还能提升请求处理性能。
4. 验证Serverless私有路由配置
- 确认两个路由的
private: true配置关联到同一API Key或使用计划,避免鉴权规则不一致。 - 登录API Gateway控制台,检查两个路由的"Method Request"配置,确保
API Key Required均设为true,鉴权方式完全一致。
5. 查看详细请求日志
在API Gateway阶段设置中开启"Full Request/Response Logs",查看重定向请求的完整头信息,确认x-api-key是否被正确传递,以及API Gateway返回Forbidden的具体触发原因。
内容的提问来源于stack exchange,提问作者Tunnelvisie

