FastAPI中如何从一个API调用另一个API并存储响应内容?
解决FastAPI/Starlette中获取并存储第三方API响应的问题
我明白你的困扰——想用后端获取另一个API的响应并存储,但用RedirectResponse根本拿不到内容,还碰到了“Entity not found”的错误。其实问题出在你对RedirectResponse的理解上,咱们一步步来解决:
为什么RedirectResponse不行?
RedirectResponse是告诉客户端浏览器/请求工具去重新请求目标API,而不是让你的后端自己去调用目标API。这意味着你的后端完全没参与到目标API的请求过程中,自然拿不到它的响应内容,打印看不到结果也就不奇怪了。
正确的做法:后端主动调用目标API
想要拿到并存储响应,得让你的后端作为客户端,主动向目标API发送POST请求。这里推荐用httpx(FastAPI官方推荐的HTTP客户端,和Starlette完美兼容),下面是具体步骤:
1. 安装httpx
先装好依赖:
pip install httpx
2. 示例代码(异步版,FastAPI推荐)
这个例子里,咱们先获取客户端发来的请求头和请求体,再转发给目标API,拿到响应后存储到文件,最后返回自定义结果给客户端:
from fastapi import FastAPI, Request import httpx app = FastAPI() @app.post("/your-endpoint") async def handle_incoming_request(request: Request): # 拿到客户端的请求体和请求头 client_request_body = await request.json() client_request_headers = dict(request.headers) # 过滤掉不需要转发的请求头(比如Host,httpx会自动处理) headers_to_remove = ["Host", "Content-Length"] for header in headers_to_remove: client_request_headers.pop(header, None) # 目标API的地址 target_api_url = "https://your-target-api.com/apiname/" # 主动调用目标API async with httpx.AsyncClient() as client: try: target_response = await client.post( target_api_url, json=client_request_body, headers=client_request_headers ) # 如果目标API返回错误状态码,直接抛出异常方便调试 target_response.raise_for_status() except httpx.HTTPStatusError as e: return {"error": f"调用目标API失败: {str(e)}", "response_content": e.response.text} except httpx.RequestError as e: return {"error": f"网络请求错误: {str(e)}"} # 把响应内容存储到文件(根据需求选格式,这里存成JSON) with open("target_api_response.json", "w", encoding="utf-8") as f: f.write(target_response.text) # 这里可以返回你想给客户端的任意响应,比如成功提示 return {"status": "success", "message": "目标API响应已成功存储"}
3. 解决“Entity not found”错误
如果运行后还是碰到这个错误,大概率是这几个原因:
- 目标API URL错误:检查路径拼写、是否少了斜杠,比如是不是应该是
/apiname而不是/apiname/,或者域名有误。 - 请求体格式不匹配:目标API可能需要
form-data而非JSON,或者字段名、结构不对。可以打印client_request_body确认,或者看目标API的文档要求。 - 请求头缺失/错误:有些API需要认证头(比如
Authorization: Bearer xxx),或者Content-Type必须设为application/json。可以在转发前手动添加必要的头。 - 调试技巧:在异常处理里打印
target_response.text,看看目标API返回的具体错误信息,能快速定位问题。
额外提示
- 如果处理大文件响应,用流式写入避免内存溢出:
with open("large_response.bin", "wb") as f: async for chunk in target_response.aiter_bytes(): f.write(chunk) - 如果需要同步处理请求(比如你的项目是同步架构),把路由改成同步版,用
httpx.Client()代替AsyncClient即可。
内容的提问来源于stack exchange,提问作者Sudip Kandel




