e13574f6f1
- 添加 updateMessageCardsForPartialApprove 方法处理会签部分通过 - 会签一人通过后,其他人的消息卡片显示进度并保留按钮 - 修复 Dockerfile 构建顺序问题 - 修复前端类型定义问题 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.2 KiB
4.2 KiB
飞书消息 Emoji 编码修复报告
修复日期: 2026-03-01 修复分支: feature/debug-feishu-message 问题: 飞书 API 拒绝接受包含 emoji 的消息卡片
问题描述
错误信息
ErrCode: 200621;
ErrMsg: parse card json err, please check whether the card json is correct
根本原因
双重 JSON 编码问题:
-
第一次编码:
FeishuNotificationService先进行 JSON 编码$content = json_encode(['card' => $card]); -
第二次编码:
HttpClient::httpPost()对整个数据再次编码curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); -
结果:Emoji 被转义成 Unicode 序列
🔔→\ud83d\udd14📋→\ud83d\udccb✅→\u2705
-
飞书 API:不接受这种编码格式,返回 200621 错误
修复方案
1. HttpClient 统一编码
文件: backend/app/util/HttpClient.php:92
添加 JSON_UNESCAPED_UNICODE 标志:
public static function httpPost(
string $url,
array $data = [],
array $headers = [],
int $timeout = 0
): array {
// ...
// 使用 JSON_UNESCAPED_UNICODE 避免 emoji 被转义
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
// ...
}
2. FeishuNotificationService 直接传数组
文件: backend/app/service/FeishuNotificationService.php:574
修改前:
$content = json_encode(['card' => $card]);
$response = HttpClient::httpPost(
"https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id",
[
'receive_id' => $feishuUserId,
'msg_type' => 'interactive',
'content' => $content, // 已编码的字符串
],
['Authorization: Bearer ' . $token]
);
修改后:
$response = HttpClient::httpPost(
"https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id",
[
'receive_id' => $feishuUserId,
'msg_type' => 'interactive',
'content' => ['card' => $card], // 直接传递数组
],
['Authorization: Bearer ' . $token]
);
3. 同样修复 updateMessageCards 方法
文件: backend/app/service/FeishuNotificationService.php:715
'content' => ['card' => $updatedCard], // 直接传递数组
修复验证
JSON 编码测试结果
$ docker exec x-server-backend php /app/test_emoji_fix.php
测试1: JSON 编码测试
- ✅ PASS: Emoji 保持原样
测试3: 编码方式对比
默认编码: {"emoji":"\ud83d\udd14 \u901a\u77e5"}
修复编码: {"emoji":"🔔 通知"}
- ✅ PASS: 修复成功
影响范围
修复的方法
FeishuNotificationService::sendMessage()- 发送审批通知消息FeishuNotificationService::updateMessageCards()- 更新消息卡片
修复的消息类型
- 审批通知消息
- 系统通知消息
- 结果通知消息
部署状态
| 环境 | 状态 | 说明 |
|---|---|---|
| 开发环境 | ✅ 已部署 | feature/debug-feishu-message 分支 |
| 生产环境 | ✅ 已部署 | 45.153.130.80 |
相关文件
| 文件 | 修改内容 |
|---|---|
backend/app/util/HttpClient.php |
添加 JSON_UNESCAPED_UNICODE 标志 |
backend/app/service/FeishuNotificationService.php |
直接传递数组,不再预先编码 |
技术说明
JSON_UNESCAPED_UNICODE 标志
PHP 的 json_encode() 默认会将非 ASCII 字符(包括 emoji)转义成 Unicode 序列。
使用 JSON_UNESCAPED_UNICODE 标志后:
- Unicode 字符保持原样输出
- Emoji 字符保持原样输出
- 飞书 API 能正确解析
示例对比
$data = ['emoji' => '🔔 通知'];
// 默认编码
json_encode($data);
// {"emoji":"\ud83d\udd14 \u901a\u77e5"}
// 使用 JSON_UNESCAPED_UNICODE
json_encode($data, JSON_UNESCAPED_UNICODE);
// {"emoji":"🔔 通知"}
待验证
- ⏳ 实际发送飞书消息验证(需要有效的 tenant_access_token 和 user_id)
- ⏳ 验证所有消息类型(审批通知、系统通知、结果通知)
- ⏳ 验证消息卡片更新功能
报告生成时间: 2026-03-01 修复状态: ✅ 完成