Files
iotlcm/README.md
T
MiFaZhan 4fb1016977 chore: 初始开源发布
iotlcm-sms:独立短信 HTTP/gRPC 服务,支持阿里云与腾讯云。

- Go module 迁移至 git.5iot.com/iotlcm-public/iotlcm-sms
- 补 Apache-2.0 LICENSE,重写 README(特性/配置/接口/部署/目录/测试)
- 配置改为 config.example.yaml + SMS_* 环境变量注入,仓库不含真实凭证
- 清理内部标识(私有镜像仓库 / 公司名 / 客户签名 / 真实模板ID / 真实手机号)
- 统一 LF 行尾并加 .gitattributes
2026-10-22 14:21:47 +08:00

207 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iotlcm-sms
独立短信发送服务,HTTP + gRPC 双协议共用同一套实现,支持**阿里云**与**腾讯云**短信。
服务自身可持有全局供应商凭证与签名,调用方只需传模板 ID 和短信内容;也可以在每次请求里显式传入完整凭证,由调用方自行管理。
## 特性
- **双协议**:`POST /api/v1/sms/send`(HTTP)与 `PbNotice.Notice/Send`(gRPC)共用 `internal/sms` 实现
- **双供应商**:`serviceType=1` 阿里云、`serviceType=2` 腾讯云
- **配置三级合并**:`config.yaml` 默认值 → `SMS_*` 环境变量覆盖 → 调用方请求显式字段优先
- **凭证不落库**:真实凭证只放在服务器上的 `config.yaml`(只读挂载),仓库内只保留 `config.example.yaml`
- **健康检查**:`GET /healthz`
- **gRPC reflection**:可直接用 `grpcurl` 查看线上接口
## 快速开始
```bash
go mod tidy
go run .
```
默认监听 `:8080`,gRPC 默认监听 `:11200`:
```bash
HTTP_ADDR=:9090 GRPC_ADDR=:11201 go run .
```
健康检查:
```bash
curl http://127.0.0.1:8080/healthz
```
## 配置
### 配置文件
查找顺序:`SMS_CONFIG_FILE` 指定路径 → `./config.yaml` → `./config/config.yaml` → `/app/config/config.yaml`。
```yaml
# config.yaml(真实凭证只放服务器,不要提交 Git)
serviceType: "1" # 1=阿里云,2=腾讯云
regionId: cn-hangzhou
accessKeyId: ""
accessKeySecret: ""
signName: "示例签名"
# templateId: "" # 模板 ID 由调用方按业务场景传入
# sdkAppId: "" # 仅腾讯云需要
```
### 环境变量
| 变量 | 作用 |
|---|---|
| `SMS_SERVICE_TYPE` | 1=阿里云,2=腾讯云 |
| `SMS_REGION_ID` | 区域 ID,默认 `cn-hangzhou` |
| `SMS_ACCESS_KEY_ID` | AccessKey ID |
| `SMS_ACCESS_KEY_SECRET` | AccessKey Secret |
| `SMS_SDK_APP_ID` | 腾讯云 SDKAppID |
| `SMS_SIGN_NAME` | 短信签名 |
| `SMS_TEMPLATE_ID` | 默认模板 ID(通常由调用方按场景传入) |
| `SMS_CONFIG_FILE` | 指定配置文件路径 |
| `HTTP_ADDR` | HTTP 监听地址,默认 `:8080` |
| `GRPC_ADDR` | gRPC 监听地址,默认 `:11200` |
启动日志会打印实际加载的配置来源(`file=... env=...`),便于排查。
## 发送短信
### 阿里云
```bash
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": "138****8000",
"msgContent": "{\"code\":\"123456\"}"
}
}'
```
### 腾讯云
```bash
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": "138****8000",
"msgContent": "123456|5"
}
}'
```
- `serviceType=1`(阿里云)时 `msgContent` 为模板参数 JSON
- `serviceType=2`(腾讯云)时多个模板参数用 `|` 分隔
- 多个手机号用英文逗号分隔;腾讯云号码使用 E.164 格式
成功响应:
```json
{
"code": 0,
"message": "发送成功",
"data": {
"provider": "aliyun",
"requestId": "provider-request-id"
}
}
```
参数错误返回 HTTP 400,上游短信平台调用失败返回 HTTP 502。响应体中的 `code` 同步表示业务结果。
## gRPC 接口
接口名:`PbNotice.Notice/Send`。
请求中的 `config` 和 `params` 是 JSON 编码的 bytes,字段内容与 HTTP 接口一致;响应结果放在 `head.code` 和 `head.message`,`routerId`、`traceId` 原样返回。
protobuf 源文件位于 `proto/`,生成的客户端与服务端代码位于 `api/pb/`。
```bash
grpcurl -plaintext 127.0.0.1:11200 list
grpcurl -plaintext 127.0.0.1:11200 describe PbNotice.Notice
```
## 容器化部署
```bash
docker build -t iotlcm-sms:latest -f build/Dockerfile .
```
生产部署推荐用不可变版本标签:
```bash
IOTLCM_SMS_IMAGE=<your-registry>/iotlcm-sms:<commit> docker compose -f deploy/docker-compose.yml up -d
```
`deploy/docker-compose.yml` 的约定:
- HTTP 端口 `11190`,gRPC 端口 `11200`
- 真实凭证放在 `deploy/config.yaml`(**不入库**),以只读方式挂载到 `/app/config/config.yaml`
- 容器 `read_only: true`,仅 `/tmp` 为 tmpfs,启用 `no-new-privileges`
## 目录结构
```text
iotlcm-sms/
├── main.go # HTTP + gRPC 装配、环境变量注入
├── api/pb/ # 生成的 protobuf 代码
├── proto/ # protobuf 源文件
├── internal/sms/ # Provider 接口 + Registry + 供应商实现
│ ├── aliyun/ # 阿里云实现
│ └── tencent/ # 腾讯云实现
├── internal/httpapi/ # HTTP 路由与处理器
├── internal/grpcapi/ # gRPC 服务实现
├── examples/ # HTTP / gRPC 示例客户端与请求样例
├── tools/ # 辅助工具(如列出阿里云模板)
├── build/Dockerfile # 多阶段构建
└── deploy/ # docker-compose 编排
```
## 测试
```bash
go test ./...
```
`go test ./...` 不访问真实短信平台。
示例客户端:
```bash
go run ./examples/http_client
go run ./examples/http_client http://127.0.0.1:9090/api/v1/sms/send
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
```
`examples/requests/aliyun.json`、`tencent.json` 使用环境变量占位符,可入库;同目录的 `*.local.json` 是含本机测试凭证的可直接重放请求,已被 `.gitignore` 排除。
## 相关项目
本服务是 [iotlcm](https://git.5iot.com/iotlcm-public) 物联网卡全生命周期管理平台的一部分,负责向客户与设备侧下发短信通知(到期提醒、告警通知等)。
## License
[Apache License 2.0](./LICENSE)