一、推荐的系统架构
前端网页或移动App不应直接保存短信API密钥,也不应直接调用供应商接口。正确方式是由企业服务端接收业务请求,完成用户权限、频率、风控和模板校验后,再调用短信平台。
建立统一消息服务可以避免多个业务系统分别维护供应商代码,并方便后续切换路由、统一状态和实施安全控制。
二、通用请求示例
以下为通用结构示例,不代表某个平台固定字段,实际接入应以正式API文档为准:
POST /v1/messages
Authorization: Bearer <server-side-api-key>
Idempotency-Key: order_20260716_001
Content-Type: application/json
{
"to": "+国家码手机号",
"message_type": "transactional",
"template_id": "order_shipped",
"variables": {
"order_no": "TP20260716001",
"carrier": "物流公司"
},
"client_reference": "order_20260716_001"
}
号码应采用统一国际格式。模板变量需要在服务端校验,不能把未经处理的用户输入直接发送。业务流水号用于关联企业订单、用户操作和平台message ID。
三、API认证和密钥安全
- API密钥只保存在服务端环境变量或密钥管理系统。
- 测试、预发布和生产环境使用不同密钥。
- 按应用和团队实施最小权限。
- 支持IP限制、密钥轮换和异常调用告警。
- 日志中不得输出完整密钥或Authorization头。
- 发现泄露后立即撤销并生成新密钥。
不要把密钥写入Vue、JavaScript、移动App安装包或公开代码仓库。即使前端代码经过压缩,也可以被用户下载和分析。
四、幂等与重复发送控制
网络超时可能发生在平台已经接收请求之后。如果客户端直接重新发送,用户可能收到重复短信。建议为每个业务事件生成唯一幂等键,例如订单号、事件类型和状态版本的组合。
企业数据库还应对“业务ID+短信类型”建立唯一约束。收到相同事件时,先查询原发送记录;只有确认未创建请求时才提交。
五、同步响应和最终状态
API响应通常包含请求结果和message ID。企业应立即保存message ID,但不能把同步成功直接标记为delivered。最终状态需要通过Webhook或查询接口获得。
{
"message_id": "msg_01J...",
"client_reference": "order_20260716_001",
"status": "accepted"
}
系统应分别保存submitted、accepted、sent、delivered、failed和expired等统一状态,同时保留供应商原始状态及错误码。
六、队列、限流与批量发送
验证码和关键通知应使用高优先级队列,营销群发使用独立低优先级队列。不要让大型活动阻塞登录验证码。平台返回429时应降低速度,并根据文档或指数退避规则重试。
| 场景 | 推荐方式 |
|---|---|
| 登录验证码 | 单条快速提交,高优先级,短有效期 |
| 订单通知 | 事件驱动,幂等,状态可追踪 |
| 批量营销 | 分批、平滑发送、预算和频率控制 |
| 历史数据导入 | 离线任务,校验、去重和退订过滤 |
七、错误和重试处理
认证错误、参数错误、号码无效和模板拒绝属于永久错误,应修正后再创建新请求;网络超时、限流和临时路由不可用可以有限重试。
重试需要最大次数、递增间隔、随机抖动和消息有效期。验证码过期后不应继续重试旧消息。所有失败都应保存原始错误码、统一分类、attempt次数和最后处理结果。
八、上线前检查清单
- 确认接口只从服务端调用,密钥没有进入前端资源。
- 验证国际号码格式、模板变量和短信分段。
- 完成幂等、超时、限流和重复请求测试。
- 接入Webhook验签、事件去重和乱序处理。
- 建立状态映射、错误分类和最终送达报表。
- 分别测试OTP、通知和营销流量。
- 设置发送量、失败率、延迟和费用告警。
- 先小流量灰度,再逐步扩大国家和并发。