阿里云dysmsapi接口要求templateparam为合法json字符串,推荐用json.marshal生成;signname和templatecode须从控制台复制;region_id需与资源创建地域一致;gin中需加context超时控制;redis验证码key应含scene字段并设ttl为300秒。

templateParam 字符串拼接必须是合法 JSON
阿里云 Dysmsapi 接口要求 TemplateParam 是标准 JSON 字符串,不是 PHP/Go 的关联数组或 map 直接传入。常见错误是用 fmt.Sprintf("{\"code\":\"%s\"}", code) 但没做转义,导致含双引号、反斜杠或中文时 JSON 解析失败,返回 InvalidJSONParam。
- Go 中推荐用
json.Marshal(map[string]string{"code": code})生成,避免手拼 - 如果硬要手拼,必须对
code值调用strings.ReplaceAll过滤双引号和换行符 - 模板里变量名(如
${code})和 JSON key 必须完全一致、大小写敏感,${CODE}和{"code": "123"}不匹配 - 签名名
SignName和模板码TemplateCode务必从阿里云控制台**复制粘贴**,全角空格、括号、标点错一个就报InvalidSignName或TemplateNotFound
accessKeyId / accessKeySecret 必须配 region_id 且时区一致
阿里云 Go SDK 初始化 client 时,region_id 不只是地域标识,它决定了请求 endpoint 和签名计算方式。用错 region(比如填了 cn-beijing 却在杭州控制台申请的模板),会返回 SignatureDoesNotMatch。
- 国内默认用
cn-hangzhou,哪怕你服务器在成都或深圳,只要控制台创建资源时选的是华东1(杭州)就得填这个 - SDK 内部用系统时间生成
X-ACS-Date头,若服务器时间与 NTP 不同步(偏差 >5 分钟),直接拒收;建议加一行ntpdate -s time.windows.com或用 systemd-timesyncd 校准 -
accessKeyId和accessKeySecret必须是主账号或具备AliyunDysmsFullAccess策略的子账号凭证,RAM 子用户需显式授权
Gin 路由里发短信必须带 context 超时控制
短信接口平均响应 300–800ms,但网络抖动或阿里云限流时可能卡住 5s+。Gin 默认无超时,一个慢请求会拖垮整个 goroutine,高并发下容易积压连接。
- 用
context.WithTimeout(c.Request.Context(), 3*time.Second)包一层再传给 SDK client - 不要在 handler 里直接调
client.SendSms(request),而是封装成带 ctx 的函数,失败时返回具体错误而非 panic - 若 Redis 存验证码,记得
ctx同步传给redis.SetEx(ctx, ...),否则超时后 redis 操作还在跑 - 日志中记录
ctx.Err()类型(context.DeadlineExceeded还是context.Canceled),便于区分是下游超时还是前端主动断开
验证码存 Redis 时 key 设计要防撞和可清理
单纯用手机号当 key(如 sms:13800138000)会导致同一号码多次请求覆盖,且无法按业务维度批量清理(比如某天所有测试验证码)。
- key 建议组合:
sms:verify:{phone}:{scene},其中scene可取login、register、reset - TTL 设为 5 分钟(300 秒),别用 600 —— 阿里云模板里写的“5分钟有效”,用户预期就是 5 分钟
- 发新验证码前先
DEL旧 key,避免残留;但注意 DEL 不是原子操作,高并发下可用 Lua 脚本保证 - 上线前检查 Redis 是否启用了
maxmemory-policy=volatile-lru,否则过期 key 不及时回收,OOM 风险陡增











