Node.js & Express 长耗时3D模型生成API进度返回方案咨询
长耗时3D模型生成API的进度返回机制与实现方案
针对你的长耗时3D模型生成API,有几种成熟的进度返回机制,以下是具体实现方案和浏览器端读取方式:
一、可行的进度返回机制
1. 分阶段异步API(推荐,兼容性最好)
将整个流程拆分为任务提交、进度查询、结果获取三个独立接口,避免长连接占用资源。
2. Server-Sent Events (SSE)
基于HTTP的单向推送协议,服务端可保持连接并持续发送进度事件,适合不需要双向交互的场景。
3. WebSocket
全双工通信协议,支持服务端主动推送进度,同时允许客户端中途发送取消、调整参数等指令,适合交互需求复杂的场景。
4. 简单轮询(低成本快速实现)
客户端定期调用进度查询接口,实现简单但会产生冗余请求,适合小型项目或原型验证。
二、具体实现细节
1. 分阶段异步API实现
- 任务提交接口:
客户端发起POST请求后,服务端立即返回202 Accepted状态码,同时返回唯一taskId(如UUID),后台启动异步任务处理3D模型生成。# 服务端示例(Python/Flask) @app.post("/api/3d-model/generate") def submit_task(): params = request.get_json() task_id = str(uuid.uuid4()) # 存入Redis:任务状态初始化为pending,进度0% redis_client.set(f"task:{task_id}", json.dumps({ "status": "pending", "percentage": 0, "is_completed": False, "success": False, "result": None, "error": None })) # 启动后台异步任务(如用Celery) generate_3d_model.delay(task_id, params) return {"taskId": task_id}, 202 - 进度查询接口:
客户端通过taskId查询任务进度,服务端从缓存/数据库中读取并返回当前状态。 - 结果获取接口:
任务完成后,客户端通过该接口获取3D模型文本或错误信息。
2. SSE实现
服务端保持HTTP连接,通过SSE格式持续发送进度数据:
# 服务端示例(Python/Flask) @app.get("/api/3d-model/generate-sse") def generate_with_sse(): params = request.args.to_dict() def generate_progress(): # 模拟3D模型生成步骤 steps = ["拓扑构建", "纹理映射", "模型优化", "导出"] for i, step in enumerate(steps): progress = (i+1)/len(steps)*100 # SSE格式:data: {JSON数据}\n\n yield f'data: {json.dumps({"type": "progress", "percentage": progress, "status": step})}\n\n' time.sleep(60) # 模拟耗时步骤 # 发送完成结果 yield f'data: {json.dumps({"type": "complete", "modelText": "3D模型文本内容"})}\n\n' return Response(generate_progress(), mimetype="text/event-stream")
3. WebSocket实现
服务端与客户端建立WebSocket连接,实时推送进度:
# 服务端示例(Python/FastAPI) @app.websocket("/api/3d-model/generate-ws") async def generate_with_websocket(websocket: WebSocket): await websocket.accept() params = await websocket.receive_json() # 模拟生成步骤 steps = ["拓扑构建", "纹理映射", "模型优化", "导出"] try: for i, step in enumerate(steps): progress = (i+1)/len(steps)*100 await websocket.send_json({ "type": "progress", "percentage": progress, "status": step }) await asyncio.sleep(60) # 发送完成结果 await websocket.send_json({ "type": "complete", "modelText": "3D模型文本内容" }) except Exception as e: await websocket.send_json({ "type": "error", "error": str(e) }) finally: await websocket.close()
三、浏览器端读取进度的方式
1. 分阶段异步API的客户端实现
async function start3DModelGeneration(params) { // 提交任务 const initRes = await fetch("/api/3d-model/generate", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(params) }); if (initRes.status !== 202) throw new Error("任务提交失败"); const { taskId } = await initRes.json(); // 定时查询进度 const progressInterval = setInterval(async () => { const progressRes = await fetch(`/api/3d-model/progress/${taskId}`); const progressData = await progressRes.json(); console.log(`进度:${progressData.percentage}% | 状态:${progressData.status}`); if (progressData.is_completed) { clearInterval(progressInterval); if (progressData.success) { const resultRes = await fetch(`/api/3d-model/result/${taskId}`); const modelText = await resultRes.text(); // 处理3D模型文本 console.log("生成完成:", modelText); } else { console.error("生成失败:", progressData.error); } } }, 10000); // 每10秒查询一次 }
2. SSE的客户端实现
function startGenerationWithSSE(params) { const searchParams = new URLSearchParams(params); const source = new EventSource(`/api/3d-model/generate-sse?${searchParams}`); source.onmessage = (event) => { const data = JSON.parse(event.data); switch(data.type) { case "progress": console.log(`进度:${data.percentage}% | 状态:${data.status}`); break; case "complete": console.log("生成完成:", data.modelText); source.close(); break; case "error": console.error("生成失败:", data.error); source.close(); break; } }; source.onerror = (err) => { console.error("SSE连接异常:", err); source.close(); }; }
3. WebSocket的客户端实现
function startGenerationWithWebSocket(params) { const socket = new WebSocket(`ws://${window.location.host}/api/3d-model/generate-ws`); socket.onopen = () => { socket.send(JSON.stringify(params)); }; socket.onmessage = (event) => { const data = JSON.parse(event.data); switch(data.type) { case "progress": console.log(`进度:${data.percentage}% | 状态:${data.status}`); break; case "complete": console.log("生成完成:", data.modelText); socket.close(); break; case "error": console.error("生成失败:", data.error); socket.close(); break; } }; socket.onerror = (err) => { console.error("WebSocket连接异常:", err); socket.close(); }; }
四、方案选型建议
- 优先选分阶段异步API:实现简单、兼容性强,无需处理长连接的异常情况,适合大多数场景。
- 需要实时推送且无双向交互需求:选SSE,比WebSocket轻量,无需额外协议支持。
- 需要客户端中途取消、调整参数等交互:选WebSocket,全双工通信更灵活。
- 小型项目快速验证:选简单轮询,开发成本最低。
内容的提问来源于stack exchange,提问作者pcace
相关产品推荐
相关产品推荐

