iotlcm-sms
独立短信 HTTP/gRPC 服务,支持阿里云和腾讯云短信。
启动
go mod tidy
go run .
默认监听 :8080,可通过 HTTP_ADDR 修改:
HTTP_ADDR=:9090 go run .
gRPC 默认监听 :11200,可通过 GRPC_ADDR 修改。HTTP 与 gRPC 使用同一套短信发送实现。
默认供应商配置
短信服务自身持有全局凭证与签名,调用方只需传模板 ID 和短信内容。默认配置按下面的顺序合并:
config.yaml 默认值 → SMS_* 环境变量覆盖 → 调用方请求中显式提供的字段优先
配置文件查找顺序:SMS_CONFIG_FILE 指定路径 → ./config.yaml → ./config/config.yaml → /app/config/config.yaml。
# config.yaml(真实凭证只放服务器,不要提交 Git)
serviceType: "1" # 1=阿里云,2=腾讯云
regionId: cn-hangzhou
accessKeyId: ""
accessKeySecret: ""
signName: "示例企业"
可用环境变量覆盖:SMS_SERVICE_TYPE、SMS_REGION_ID、SMS_ACCESS_KEY_ID、
SMS_ACCESS_KEY_SECRET、SMS_SDK_APP_ID、SMS_SIGN_NAME、SMS_TEMPLATE_ID。
仓库内提供 config.example.yaml 作为模板;.gitignore 已排除真实 config.yaml。
启动日志会打印实际加载的配置来源(file=... env=...),便于排查。
场景模板配置库(可选)
除全局凭证外,还支持按业务场景(scene)从数据库回填模板与签名:调用方只传 scene
和内容参数,无需关心具体模板 ID。连接参数与凭证同放 config.yaml:
# 场景模板配置库(表 t_sms_template_config);DSN 留空或省略 = 关闭该能力
sceneDbDsn: "user:pass@tcp(127.0.0.1:3306)/db_iotlcm?charset=utf8mb4&parseTime=true&loc=Local"
sceneDbCacheTtl: 60s # 场景配置内存缓存时长,"改库即生效"的最长延迟
可用环境变量覆盖:SMS_DB_DSN、SMS_DB_CONFIG_CACHE_TTL。DSN 未配置时,
带 scene 的请求返回 400(短信场景未配置或已停用)。
生产环境使用 deploy/docker-compose.yml 容器化部署,HTTP 端口为 11190,
gRPC 端口为 11200。
docker build --platform linux/amd64 -f build/Dockerfile \
-t <your-registry>/iotlcm-sms:latest .
docker push <your-registry>/iotlcm-sms:latest
cd deploy
# 先在服务器放置真实 config.yaml(不入库)
docker compose pull
docker compose up -d
生产部署建议通过 IOTLCM_SMS_IMAGE 指定不可变版本标签:
IOTLCM_SMS_IMAGE=<your-registry>/iotlcm-sms:<commit> docker compose up -d
健康检查:
curl http://127.0.0.1:8080/healthz
发送短信
接口:POST /api/v1/sms/send
阿里云请求示例:
curl -X POST http://127.0.0.1:8080/api/v1/sms/send \
-H 'Content-Type: application/json' \
-d '{
"config": {
"serviceType": "1",
"regionId": "cn-hangzhou",
"accessKeyId": "your-access-key-id",
"accessKeySecret": "your-access-key-secret",
"signName": "your-sign-name",
"templateId": "SMS_000000001"
},
"params": {
"phoneNumber": "13800008000",
"msgContent": "{\"code\":\"123456\"}"
}
}'
腾讯云请求示例:
curl -X POST http://127.0.0.1:8080/api/v1/sms/send \
-H 'Content-Type: application/json' \
-d '{
"config": {
"serviceType": "2",
"sdkAppId": "1400000000",
"accessKeyId": "your-secret-id",
"accessKeySecret": "your-secret-key",
"signName": "your-sign-name",
"templateId": "000000"
},
"params": {
"phoneNumber": "+8613800138000",
"msgContent": "123456|5"
}
}'
serviceType 为 1 时使用阿里云,msgContent 应为模板参数 JSON。serviceType 为 2 时使用腾讯云,多个模板参数继续沿用原项目的 | 分隔格式。多个手机号使用英文逗号分隔,腾讯云号码应使用 E.164 格式。
成功响应:
{
"code": 0,
"message": "发送成功",
"data": {
"provider": "aliyun",
"requestId": "provider-request-id"
}
}
参数错误返回 HTTP 400,上游短信平台调用失败返回 HTTP 502。响应体中的 code 同步表示业务结果。
测试实例
运行不访问真实短信平台的 HTTP 接口测试:
go test ./...
运行示例客户端(先启动服务并替换示例中的测试凭证):
go run ./examples/http_client
也可以传入其他服务地址:
go run ./examples/http_client http://127.0.0.1:9090/api/v1/sms/send
gRPC 接口
迁移后的接口保持原服务 protobuf 兼容:
PbNotice.Notice/Send
请求中的 config 和 params 是 JSON 编码的 bytes,字段内容与 HTTP 接口一致。
响应结果放在 head.code 和 head.message 中;routerId、traceId 会原样返回。
protobuf 源文件位于 proto,生成的客户端和服务端代码位于 api/pb。
使用 Go 示例客户端发送请求:
go run ./examples/grpc_client examples/requests/aliyun.local.json
go run ./examples/grpc_client examples/requests/tencent.local.json 127.0.0.1:11200
服务注册了 gRPC reflection,可查看线上接口:
grpcurl -plaintext 127.0.0.1:11200 list
grpcurl -plaintext 127.0.0.1:11200 describe PbNotice.Notice
已保存的 HTTP 请求示例位于 examples/requests。其中 aliyun.json 和
tencent.json 使用环境变量占位符,可用于文档和版本管理;同目录的
*.local.json 是包含本机测试凭证的可直接重放请求,已被 .gitignore 排除。
curl -X POST http://127.0.0.1:8080/api/v1/sms/send \
-H 'Content-Type: application/json' \
--data-binary @examples/requests/aliyun.local.json
curl -X POST http://127.0.0.1:8080/api/v1/sms/send \
-H 'Content-Type: application/json' \
--data-binary @examples/requests/tencent.local.json