Go发短信需用显式http.Client设8秒超时、区分三类错误、隔离敏感信息;优先选阿里云SDK v3,互亿无线签名须MD5(apikey+10位时间戳);验证码场景须限流、手机号去重、参数外置。

Go 语言发短信不是写个 http.Post 就完事——它本质是调用第三方 HTTP API,成败关键在错误分类、超时控制和敏感信息隔离。
用 http.Client 而不是 http.Post 发请求
裸调 http.Post 看似简单,但一卡住就永远阻塞,线上服务可能因此 goroutine 泄漏。阿里云、互亿无线等所有短信接口都要求明确超时、可重试、能区分网络/HTTP/业务三类错误。
- 必须显式构造
*http.Client,设Timeout: 8 * time.Second(别用默认的无限等待) - 别漏掉
Content-Type: application/x-www-form-urlencoded(互亿无线)或application/json(阿里云),否则返回415 Unsupported Media Type - 响应体要先检查
resp.StatusCode,再解析 JSON/XML;否则401 Unauthorized也会被当成“成功发送”
阿里云 SDK v3 和老版 alibaba-cloud-sdk-go 怎么选
v3(github.com/alibabacloud-go/dysmsapi-20170525/v3)是官方主推,支持自动签名、重试、OpenAPI 统一认证;老版(github.com/aliyun/alibaba-cloud-sdk-go)已归档,不维护,且不兼容新版凭证链(比如环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID)。
- 新项目直接上 v3,初始化用
openapi.Config+dysms.Client,别用NewClientWithAccessKey - 老版里
request.TemplateParam是字符串,v3 里必须用tea.String(...)包一层 - v3 的
SendSmsWithOptions支持传*util.RuntimeOptions控制重试、压缩、超时,老版做不到
互亿无线 GET 接口的 password 动态签名怎么算
互亿无线强制要求 MD5(apikey + timestamp),且 time 参数必须是 10 位 Unix 时间戳(time.Now().Unix()),不是毫秒。错一位、多一个空格、编码没统一为 UTF-8,都会返回 code=4(签名错误)。
立即学习“go语言免费学习笔记(深入)”;
- 别手写 MD5,用标准库:
fmt.Sprintf("%x", md5.Sum([]byte(apikey+strconv.FormatInt(ts, 10)))) - GET 请求参数拼接顺序必须严格按文档:
account、password、mobile、content、time - 测试期只能用默认签名
【互亿无线】和默认模板,换别的会直接拒单,返回msg=模板未审核通过
验证码场景下最容易被忽略的三个点
不是“能发出去”就算完成——高并发注册/登录时,短信服务本身会限流,客户端不做防护,轻则触发平台封禁,重则压垮自己服务。
- 加客户端限流:
rate.NewLimiter(rate.Every(1*time.Second), 5),防止突发流量打爆服务商配额 - 手机号去重:同一号码 60 秒内重复请求,直接返回缓存的
BizId或拒绝,避免用户狂点“重发” - 敏感参数全外置:把
accessKeyID、templateCode、signName全部从os.Getenv或配置文件读,硬编码进代码 = 提交即泄露
真正难的从来不是“怎么调通接口”,而是当 429 Too Many Requests 或 isv.BUSINESS_LIMIT_CONTROL 出现时,你的程序能不能安静降级、记录上下文、不崩不吵。


















