feat: 支持 HTTP 回调和 WebSocket 长连接两种模式

新增功能:
- 通过 FEISHU_MODE 配置切换模式 (http/websocket)
- 安装飞书 SDK (@larksuiteoapi/node-sdk)
- WebSocket 模式支持内网部署(无需公网 IP)
- 新增 WEBSOCKET.md 配置指南

更新:
- README.md 添加两种模式说明
- .env.example 添加 FEISHU_MODE 配置
- 健康检查返回当前模式信息
This commit is contained in:
饭团
2026-03-05 16:42:17 +08:00
parent 5294bf49d8
commit 3769d164b1
6 changed files with 499 additions and 11 deletions

View File

@@ -8,6 +8,7 @@
* 2. 支持交互式卡片上传
* 3. 支持命令触发上传
* 4. 配置管理
* 5. 支持 HTTP 回调和 WebSocket 长连接两种模式
*/
require('dotenv').config();
@@ -21,8 +22,14 @@ const { QiniuUploader } = require('./qiniu-uploader');
const { UploadCard } = require('./cards/upload-card');
const { ConfigCard } = require('./cards/config-card');
// 飞书 SDKWebSocket 模式)
const { Api, eventSubscription } = require('@larksuiteoapi/node-sdk');
const app = express();
const PORT = process.env.PORT || 3000;
const PORT = process.env.PORT || 3030;
// 运行模式:'http' 或 'websocket'
const MODE = (process.env.FEISHU_MODE || 'http').toLowerCase();
// 中间件
app.use(express.json());
@@ -299,13 +306,89 @@ app.post('/feishu/event', handleFeishuEvent);
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
mode: MODE,
port: PORT
});
});
// ============ 启动服务 ============
app.listen(PORT, () => {
log(`🚀 七牛云上传机器人启动`);
log(`📍 端口:${PORT}`);
log(`🔗 事件地址https://your-domain.com/feishu/event`);
});
function startHTTPMode() {
app.listen(PORT, () => {
log(`🚀 七牛云上传机器人启动 (HTTP 回调模式)`);
log(`📍 端口:${PORT}`);
log(`🔗 事件地址http://your-domain.com:${PORT}/feishu/event`);
log(`💡 提示:在飞书开放平台配置事件订阅地址为上述地址`);
});
}
function startWebSocketMode() {
log(`🚀 七牛云上传机器人启动 (WebSocket 长连接模式)`);
log(`💡 提示:在飞书开放平台选择 "WebSocket 长连接" 方式`);
// 创建飞书客户端
const client = new Api({
appId: process.env.FEISHU_APP_ID,
appSecret: process.env.FEISHU_APP_SECRET,
});
// 创建 WebSocket 长连接
const ws = eventSubscription({
appId: process.env.FEISHU_APP_ID,
appSecret: process.env.FEISHU_APP_SECRET,
encryptKey: process.env.FEISHU_ENCRYPT_KEY,
verificationToken: process.env.FEISHU_VERIFICATION_TOKEN,
logLevel: 'info',
});
// 监听消息事件
ws.on('im.message.receive_v1', async (data) => {
log('收到消息事件');
await handleMessage(data);
});
// 监听连接状态
ws.on('open', () => {
log('✅ WebSocket 连接成功');
});
ws.on('close', () => {
log('❌ WebSocket 连接关闭5 秒后重连...');
setTimeout(() => {
try {
ws.start();
} catch (e) {
log('重连失败:', e.message);
}
}, 5000);
});
ws.on('error', (error) => {
log('❌ WebSocket 错误:', error.message);
});
// 启动 WebSocket 连接
try {
ws.start();
log('📡 WebSocket 已启动');
} catch (error) {
log('❌ WebSocket 启动失败:', error.message);
log('💡 请检查飞书配置是否正确');
}
// HTTP 服务器仍然运行(用于健康检查)
app.listen(PORT, () => {
log(`📍 健康检查端口:${PORT}`);
log(`🔗 健康检查地址http://localhost:${PORT}/health`);
});
}
// 根据配置启动对应模式
if (MODE === 'websocket') {
startWebSocketMode();
} else {
startHTTPMode();
}