Revel框架调用短信接口需设Content-Type为application/x-www-form-urlencoded、显式UTF-8编码、超时控制、验证码存Redis、校验服务商返回的业务code而非HTTP状态码,并配置IP白名单。

Revel 框架本身不内置短信能力,对接短信接口本质是「在 Revel 的 Controller 里发起 HTTP 请求调用第三方服务商 API」,关键不在框架特性,而在参数构造、错误处理和状态流转是否健壮。直接写 http.Post 很容易漏掉签名校验、UTF-8 编码、超时控制、模板变量拼接这些细节,上线后收不到短信或被限流才是真问题。
Revel 中调用短信接口必须设置的请求头和编码
Revel 默认用 net/http,但很多开发者忽略服务商强制要求的请求头和字符集,导致返回 405 或乱码短信(比如验证码变成“?123456?”)。
-
Content-Type必须设为application/x-www-form-urlencoded,不能用application/json—— 即使服务商文档说“支持 JSON”,其短信提交接口(如/sms/Submit.json)实际只认表单编码 - 所有中文内容(包括签名、模板文案)必须显式用
url.QueryEscape处理,不能依赖框架自动编码;Revel 的c.Params或c.RenderArgs不会帮你做这步 - 建议在
app.Init阶段全局配置 HTTP client,设置Timeout: 10 * time.Second,避免短信接口卡住整个请求链路
验证码发送逻辑必须和 Revel 的 session/cookie 分离
新手常把验证码存进 c.Session 或写进 cookie,结果用户换设备、清缓存就验证失败,还容易被 XSS 窃取。Revel 的 session 默认基于 cookie,不适合存敏感临时数据。
- 验证码必须存在服务端可持久化存储中,推荐
Redis,key 设为sms:verify:{mobile}:{scene},TTL 显式设为 300 秒(别依赖 Redis 默认过期) - 不要用
c.RenderJSON直接返回验证码明文,哪怕只是调试 —— 日志里一搜就暴露 - Revel 的
Filter可以统一加频控,比如对/api/send_code接口限制「同一手机号 60 秒内最多 1 次」,用 Redis 的INCR + EXPIRE原子操作实现
服务商返回的 code 字段不是 HTTP 状态码,而是业务码
Revel 的 c.Result 返回的是 HTTP 状态(如 200/400),但短信服务商响应体里的 code 是他们自己的业务标识,比如互亿无线返回 {"code":2,"msg":"提交成功","data":{"smsid":"xxx"}},这里的 code==2 才代表短信真正进了通道。
- 别只检查
resp.StatusCode == 200就认为发送成功;必须json.Unmarshal响应体,判断code是否等于预期值(不同厂商值不同:互亿无线是2,阿里云是OK,腾讯云是0) - 遇到
code==4072(模板不匹配)这类错误,要立刻比对请求中的templateid和服务商后台备案的 ID 是否一致,变量名(如${code})是否和TemplateParam传入的 key 完全相同 - 日志里必须记录原始响应体,而不是只打
err—— 很多问题靠msg字段就能定位,比如"签名未审核通过"
最常被跳过的一步:没配 IP 白名单。Revel 应用部署后出口 IP 和本地调试时完全不同,服务商看到陌生 IP 直接拒绝,错误码可能是 405 或 403,但 msg 里写的却是“账户异常”,让人误以为是密钥错了。上线前务必确认服务器公网 IP 已加到服务商控制台的白名单里。


















