先区分“调用未被接收”和“任务已接收后发送失败”。保存请求的 requestId、返回的消息 id 与查询结果,避免在排查中创建重复任务。
推荐排查顺序
- 检查 HTTP 状态和响应中的
code、message。 - 已获得消息
id时,使用原调用方密钥查询任务状态。 - 对
FAILED或UNKNOWN查看lastError,核对微信错误码或内部检查结果。 - 检查公众号、模板、接收人和业务字段;修复原因后再决定是否重试原任务。
HTTP 202 表示已入队,不能据此判断微信已接收。SENT 表示微信接口接受,不等于用户已收到或阅读。
HTTP 错误
| HTTP / code | 常见原因 | 处理方式 |
|---|---|---|
400 VALIDATION_ERROR |
必填字段缺失、空白、长度或格式不符 | 按字段表修正请求 |
400 INVALID_CRM_REQUEST |
CRM 请求不是 JSON 对象、字段类型错误或含控制字符 | 业务字段使用字符串,不传换行、制表符等控制字符 |
400 UNSUPPORTED_CRM_FIELD |
CRM 请求传入 templateId、channelId、data 等未开放字段 |
只传 CRM 文档中的业务字段 |
400 INVALID_CRM_TIME |
日期不存在或不符合严格格式 | 使用有效的 yyyy-MM-dd HH:mm 北京时间,例如 2026-10-26 11:00 |
400 INVALID_CRM_PHONE |
电话字段不包含任何数字 | 按电话号码要求提供字符串 |
400 INVALID_URL |
详情链接不是完整 HTTP/HTTPS URL | 使用包含协议和主机名的完整链接 |
400 CHANNEL_DISABLED |
通道已停用 | 由管理员核对通道状态 |
401 |
Key 或 Secret 缺失、不匹配,旧系统尚未轮换,或调用方停用 | 同时检查 X-API-Key(或 Bearer)与 X-API-Secret;通过后台轮换并交付新凭据 |
403 CHANNEL_FORBIDDEN |
调用方没有目标通道权限 | 使用获授权的业务密钥或调整该调用方权限 |
403 RECIPIENT_FORBIDDEN |
OpenID 未授权给当前调用系统及通道,或已撤销 | 管理员在该系统下核对接收人 OpenID、通道及启用状态;OpenID 区分大小写 |
403 ADMIN_REQUIRED |
业务密钥调用了管理 API | 管理操作使用管理员密钥;CRM 使用业务接口 |
404 MESSAGE_NOT_FOUND |
ID 不存在、属于其他调用方或不在当前 CRM 通道 | 使用原业务调用方密钥与正确的消息 ID |
409 IDEMPOTENCY_CONFLICT |
相同 requestId 对应不同消息内容 | 同一通知复用原内容,新通知使用新的业务标识 |
413 |
请求体超过入口限制 | API 请求体最多 64KB;同时遵守字段更小的长度限制 |
429 |
来源 IP 请求速率超过 Nginx 限制 | 延迟并退避,复用原 requestId 重试 |
503 DATABASE_UNAVAILABLE |
数据库暂时不可用 | 检查数据库服务、网络与运行配置 |
503 CRM_NOT_CONFIGURED |
CRM 通道不存在或模板配置为空 | 管理员检查 CRM 环境配置与通道 |
Nginx 在处理大小限制或限流时可能返回 HTML 错误页,调用方应先读取 HTTP 状态,不应假定所有错误响应都是 JSON。
微信发送错误
| 微信码 | 含义 | 检查内容 |
|---|---|---|
40037 / 41028 |
模板 ID 无效 | 在当前公众号的“我的模板”及中间件读取结果中重新核对完整 ID |
40003 |
接收人 OpenID 无效 | 从目标公众号的 OpenID 页面重新获取,核对是否跨公众号使用 |
43004 |
接收人未关注公众号 | 由接收人关注目标公众号后再核对 |
45015 |
超出客服消息允许的互动时限 | 接收人先在公众号会话中主动发消息,再测试客服回复 |
40164 |
接口 IP 白名单不匹配 | 核对应用服务器实际出口 IP,并更新微信后台白名单 |
40125 / 41004 |
AppSecret 无效或缺失 | 核对通道凭据与当前公众号开发配置 |
40013 |
AppID 无效 | 核对通道归属与 AppID |
48001 |
公众号没有接口权限 | 在公众号后台查看对应能力权限 |
45009 |
当日接口额度耗尽 | 查看公众号配额与调用量,等待或按平台流程处理 |
-1 / 45011 |
系统繁忙或调用频率受限 | 系统会在重试预算内退避重试 |
微信返回的明确错误保存在任务的 lastError 中。不要只根据模板标题推断接口类型:普通模板消息、订阅通知与一次性订阅消息需要不同的配置和授权。
模板读取成功却发送失败
读取成功说明凭据能够访问模板列表,不证明任意模板请求都可以成功。继续核对:
- 发送使用的模板 ID 与账号下最新完整 ID 完全一致。
- 模板字段名与模板内容一致;不要把公共模板编号作为发送 ID。
- 接收人的 OpenID 属于当前账号,且满足对应消息接收条件。
- 字段值符合模板类型和微信侧限制。
通过“推送测试”读取当前模板再选择,可以减少手动复制错误。当前 CRM 的字段映射由服务端固定,CRM 调用方不应传入微信字段名。
CRM 日期与字段校验
markedAt 必须显式提供,例如 2026-10-26 11:00。2026-02-30 11:00、只传日期、带秒或带时区后缀都不符合当前格式。
客户名称、类型和来源均为最多 20 字符的非空字符串。电话为 3–17 字符,只允许数字、+、括号、空格和短横线,并至少包含一个数字。字段不会自动去空格,重试时应保持值完全一致。
完整字段表与示例见CRM 推送接口。
UNKNOWN 与服务重启
发送时连接中断、微信响应异常或工作线程租约超过 5 分钟,都可能产生 UNKNOWN。此时原请求可能已经被微信接收。
先在管理控制台和接收人微信侧核对,再决定是否人工重试。不要自动换 requestId 重发,也不要将所有 PROCESSING 或 UNKNOWN 记录批量改回待发送状态。
服务启动失败时,先检查 systemd 与应用日志:
journalctl -u pushmsg -n 100 --no-pager
tail -n 100 /opt/pushmsg/shared/logs/pushmsg.log
数据库迁移失败时,核对实际结构、迁移记录和发布版本,按备份恢复方案处理。Jar 回滚不等于数据库回滚,相关步骤见构建与部署。
访问文档与业务入口
生产文档入口为 https://pmsg.admin.xianboss.com,站点目录为生产服务器上的 /www/wwwroot/pmsg.admin.xianboss.com。访问异常时,先检查域名解析、HTTPS 证书与该域名的 Nginx 站点配置。
原 http://192.168.0.21:8084 保留为局域网预览入口;pushmsg.doc 需要访问设备具备对应的内部 DNS 或 hosts 解析。
业务请求仍发送到文档中的应用地址,不能把文档站地址替换为 CRM API 的生产地址。CRM 使用 https://openid.xianboss.com/api/v1/crm/push;通用接口和管理入口的 IP HTTPS 证书需要信任交付证书。