Egg.js 中使用 egg-http-proxy 实现 Dify API 的 SSE 流式输出
在基于 Egg.js 框架开发应用时,我们经常需要代理第三方 API 接口。本文将详细介绍如何使用 egg-http-proxy 中间件来代理 Dify 平台的聊天消息接口,并实现 Server-Sent Events (SSE) 的流式输出功能。
技术背景
SSE (Server-Sent Events) 是一种服务器推送技术,允许服务器单向向客户端发送事件流。与 WebSocket 不同,SSE 是单向通信,适用于服务器向客户端推送数据的场景。Dify 平台的 /chat-messages 接口在 response_mode=streaming 参数下会返回 SSE 格式的聊天消息流。
服务端实现
在 Egg.js 项目中,我们需要创建一个控制器来处理 Dify API 的代理请求:
const Controller = require('egg').Controller;
class DifyController extends Controller {
async all() {
const { ctx, config } = this;
await ctx.proxyRequest(config.dify.host, {
streaming: true, // 启用流式传输
headers: {
Authorization: 'Bearer ' + config.dify.apiKey,
},
rewrite(urlObj) {
// 重写路径,移除/dify前缀
urlObj.pathname = urlObj.pathname.replace(/^\/dify/, '');
return urlObj;
}
});
}
}
module.exports = DifyController;
关键配置说明:
streaming: true启用流式传输模式headers中添加 Dify API 所需的认证头rewrite函数用于重写请求路径
客户端实现
客户端需要使用 EventSource 或兼容的库来接收 SSE 事件流。这里我们使用 @microsoft/fetch-event-source 库:
import { fetchEventSource } from '@microsoft/fetch-event-source'
const ctrl = new AbortController();
let loading = 'Loading...';
let answer = '';
fetchEventSource('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer {API_KEY}'
},
body: JSON.stringify({
user: 'fym',
query: 'Hello',
response_mode: 'streaming',
inputs: {}
}),
signal: ctrl.signal,
onopen: (e) => {
console.log('SSE连接已建立', e);
},
onclose: (e) => {
console.log('SSE连接已关闭', e);
loading = 'closed';
},
onerror: (e) => {
console.error('SSE错误', e);
loading = e.message;
ctrl.abort();
},
onmessage: (e) => {
try {
const data = JSON.parse(e.data);
loading = data.event;
switch (data.event) {
case 'message':
answer += data.answer;
break;
case 'end':
loading = '';
break;
case 'error':
loading = data.error;
ctrl.abort();
break;
default:
break;
}
} catch (error) {
// 忽略JSON解析错误,继续处理后续事件
console.warn('SSE数据解析异常', error);
}
}
});
注意事项
-
文件上传处理:如果需要使用 Dify 的文件上传接口,必须配置
egg-multipart的 mode 为 stream,否则会返回 400 错误。 -
错误处理:SSE 流可能会包含非 JSON 格式的数据,客户端需要妥善处理解析异常。
-
连接管理:使用 AbortController 可以灵活控制 SSE 连接的开启和关闭。
-
性能考虑:长时间保持的 SSE 连接会占用服务器资源,需要合理设计连接超时和重连机制。
总结
通过 Egg.js 的 egg-http-proxy 中间件,我们可以轻松实现 Dify API 的代理和 SSE 流式输出功能。这种方案既保持了 Egg.js 应用的架构完整性,又能充分利用 Dify 平台的流式聊天能力。在实际应用中,开发者可以根据业务需求进一步优化错误处理和连接管理逻辑。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust074- DDeepSeek-V4-ProDeepSeek-V4-Pro(总参数 1.6 万亿,激活 49B)面向复杂推理和高级编程任务,在代码竞赛、数学推理、Agent 工作流等场景表现优异,性能接近国际前沿闭源模型。Python00
MiniMax-M2.7MiniMax-M2.7 是我们首个深度参与自身进化过程的模型。M2.7 具备构建复杂智能体应用框架的能力,能够借助智能体团队、复杂技能以及动态工具搜索,完成高度精细的生产力任务。Python00
GLM-5.1GLM-5.1是智谱迄今最智能的旗舰模型,也是目前全球最强的开源模型。GLM-5.1大大提高了代码能力,在完成长程任务方面提升尤为显著。和此前分钟级交互的模型不同,它能够在一次任务中独立、持续工作超过8小时,期间自主规划、执行、自我进化,最终交付完整的工程级成果。Jinja00
Kimi-K2.6Kimi K2.6 是一款开源的原生多模态智能体模型,在长程编码、编码驱动设计、主动自主执行以及群体任务编排等实用能力方面实现了显著提升。Python00
Hy3-previewHy3 preview 是由腾讯混元团队研发的2950亿参数混合专家(Mixture-of-Experts, MoE)模型,包含210亿激活参数和38亿MTP层参数。Hy3 preview是在我们重构的基础设施上训练的首款模型,也是目前发布的性能最强的模型。该模型在复杂推理、指令遵循、上下文学习、代码生成及智能体任务等方面均实现了显著提升。Python00