---
belongs_to:
- "[[INDEX · 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]"
---
# 🔧 铸渊+舒舒指令|修复 Pipeline C 飞书广播推送 · 新增 /push-broadcast 路由(2026-03-15·霜砚签发)
---
## 一、错误日志(原文)
```
📢 推送广播到飞书...
标题: BC-M23-003-AW
目标: ou_3bd223b67374fd102edd4223244a7542
HTTP 响应: 405
405 Not Allowed
405 Not Allowed
nginx/1.24.0
❌ 推送失败 (HTTP 405)
```
---
## 二、问题分析
Pipeline C 的 `push-broadcast-feishu.sh`(或类似脚本)向服务器发送 POST 请求推送广播,但:
1. **nginx** 没有配置该路由的 proxy_pass,直接返回 405
2. **舒舒(gateway-server.js)** 没有 `/push-broadcast` 路由来接收和处理广播推送
3. 即使有路由,还需要舒舒调用**飞书发消息 API** 把广播内容发给目标用户
---
## 三、修复指令
### 3.1 舒舒:新增 /push-broadcast POST 路由
**文件位置**:`feishu-bot/index.js`(或 `gateway-server.js`,取决于实际结构)
```jsx
// ============ 广播推送路由 ============
// Pipeline C 调用此路由,将广播推送到飞书
app.post('/push-broadcast', async (req, res) => {
try {
// 1. 验证 token
const token = req.headers['x-push-token'] || req.body.token;
if (token !== process.env.PUSH_BROADCAST_TOKEN) {
return res.status(401).json({ error: 'Invalid token' });
}
// 2. 解析请求体
const { title, content, target_open_id, chat_id } = req.body;
if (!content) {
return res.status(400).json({ error: 'Missing content' });
}
// 3. 获取飞书 tenant_access_token
const tokenRes = await fetch('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
app_id: process.env.FEISHU_APP_ID,
app_secret: process.env.FEISHU_APP_SECRET
})
});
const tokenData = await tokenRes.json();
const accessToken = tokenData.tenant_access_token;
// 4. 发送飞书消息
// 优先发到群聊(chat_id),否则发给个人(target_open_id)
const receive_id_type = chat_id ? 'chat_id' : 'open_id';
const receive_id = chat_id || target_open_id;
const msgRes = await fetch(`https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receive_id_type}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify({
receive_id: receive_id,
msg_type: 'text',
content: JSON.stringify({ text: `📡 新广播 ${title || ''}\n\n${content}` })
})
});
const msgData = await msgRes.json();
if (msgData.code === 0) {
console.log(`✅ 广播推送成功: ${title} → ${receive_id}`);
res.json({ success: true, message_id: msgData.data?.message_id });
} else {
console.error(`❌ 飞书发送失败:`, msgData);
res.status(500).json({ error: msgData.msg, code: msgData.code });
}
} catch (err) {
console.error('❌ push-broadcast error:', err.message);
res.status(500).json({ error: err.message });
}
});
```
### 3.2 nginx:添加 proxy_pass(如果 /push-broadcast 没有被代理)
**文件位置**:`/etc/nginx/conf.d/guanghulab.conf`(或对应的 nginx 配置文件)
在 server block 中确认有如下配置:
```
location /push-broadcast {
proxy_pass http://127.0.0.1:3080; # 舒舒端口,按实际修改
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Content-Type $content_type;
}
```
如果舒舒已经有一个通配 location 代理所有 API 请求(如 `location /api/`),则需要确认 `/push-broadcast` 路径在代理范围内,或者单独加一条。
### 3.3 Pipeline C 脚本:确认请求格式
Pipeline C 的推送脚本应该发送如下格式的 POST 请求:
```bash
curl -X POST https://guanghulab.com/push-broadcast \
-H "Content-Type: application/json" \
-H "X-Push-Token: ${PUSH_BROADCAST_TOKEN}" \
-d '{
"title": "BC-M23-003-AW",
"content": "广播正文内容...",
"target_open_id": "ou_3bd223b67374fd102edd4223244a7542",
"chat_id": "(可选,群聊 ID)"
}'
```
---
## 四、环境变量确认
舒舒服务器上需要以下环境变量(`.env` 文件或 PM2 ecosystem):
| **变量名** | **用途** | **来源** |
| --- | --- | --- |
| `FEISHU_APP_ID` | 飞书应用 App ID | 飞书开放平台 → 应用凭证 |
| `FEISHU_APP_SECRET` | 飞书应用 App Secret | 飞书开放平台 → 应用凭证 |
| `PUSH_BROADCAST_TOKEN` | 推送鉴权 token | 与 GitHub Secret 中的 PUSH_BROADCAST_TOKEN 一致:`guanghu-push-2026` |
**注意**:`FEISHU_APP_ID` 和 `FEISHU_APP_SECRET` 舒舒发消息时就应该已经有了(舒舒接收飞书回调时用的同一个应用)。确认这两个变量在 `.env` 里存在即可。
---
## 五、验收标准
- [ ] 服务器上 `curl -X POST https://guanghulab.com/push-broadcast` 不再返回 405
- [ ] 带正确 token 和 content 的 POST 请求返回 `{"success": true}`
- [ ] 飞书端收到广播消息
- [ ] 完整链路测试:飞书发 SYSLOG → Pipeline A/B/C 全绿 → 飞书收到新广播
---
## 六、执行确认
铸渊完成后,在本页下方追加一行:
```
✅ push-broadcast 路由已部署 · [日期时间] · commit SHA
```