You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

8.6 KiB

短信服务部署指南

文档版本:v1.0
最后更新:2026-01-27


目录

  1. 前置条件
  2. 配置步骤
  3. 数据库迁移
  4. 功能测试
  5. 生产环境配置
  6. 故障排查

前置条件

1. 基础环境

  • PostgreSQL 17(已安装 UUID v7 扩展)
  • Redis(用于限流)
  • Python 3.12+
  • Celery(用于定时任务)

2. 阿里云短信服务(生产环境)

如果需要真实发送短信,需要:

  1. 注册阿里云账号
  2. 开通短信服务
  3. 配置短信签名(如:道研组)
  4. 配置短信模板(包含 ${code} 变量)
  5. 获取 AccessKey ID 和 Secret

配置步骤

1. 更新环境变量

编辑 server/.env 文件:

# ==================== 短信服务配置 ====================

# 测试模式(开发环境推荐)
SMS_TEST_MODE=True

# 生产模式配置(生产环境必填)
SMS_TEST_MODE=False
SMS_ACCESS_KEY_ID=your_access_key_id
SMS_ACCESS_KEY_SECRET=your_access_key_secret
SMS_SIGN_NAME=道研组
SMS_TEMPLATE_CODE=SMS_123456789

# ==================== Redis 配置 ====================
REDIS_URL=redis://localhost:6379/0

2. 安装依赖

确保已安装必要的 Python 包:

cd server
pip install redis httpx

或使用 requirements.txt:

pip install -r requirements.txt

数据库迁移

1. 执行迁移脚本

cd server
python app/migrations/011_sms_service_tables.py

2. 验证表结构

连接数据库,检查表是否创建成功:

-- 查看表结构
\d sms_verification_codes

-- 查看索引
\di sms_verification_codes*

-- 查看表注释
SELECT 
    col_description('sms_verification_codes'::regclass, 0) as table_comment,
    column_name,
    col_description('sms_verification_codes'::regclass, ordinal_position) as column_comment
FROM information_schema.columns
WHERE table_name = 'sms_verification_codes';

功能测试

1. 运行测试脚本

cd server
python test_sms_service.py

预期输出:

============================================================
短信服务测试
============================================================

[测试 1] 发送验证码
------------------------------------------------------------
✅ 发送成功: {'message': '验证码已发送', 'expires_in': 600}
📱 验证码: 123456
⏰ 过期时间: 2026-01-27 10:15:00

[测试 2] 验证验证码(正确)
------------------------------------------------------------
✅ 验证成功: True

[测试 3] 验证验证码(错误)
------------------------------------------------------------
❌ 验证失败(预期): 验证码不存在或已过期

[测试 4] 防刷机制(1分钟内重复发送)
------------------------------------------------------------
❌ 发送失败(预期): 验证码已发送,请稍后再试

[测试 5] 清理过期验证码
------------------------------------------------------------
🗑️  清理记录数: 0

============================================================
✅ 所有测试完成
============================================================

2. API 测试

2.1 发送验证码

curl -X POST http://localhost:6170/api/v1/auth/sms/send \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "13800138000",
    "countryCode": "+86",
    "purpose": "login"
  }'

预期响应:

{
  "code": 200,
  "message": "Success",
  "data": {
    "message": "验证码已发送",
    "expiresIn": 600
  }
}

2.2 查看日志获取验证码(测试模式)

# 查看 API 日志
docker-compose logs -f api | grep "验证码"

输出示例:

[测试模式] 跳过短信发送: phone=13800138000, code=123456

2.3 验证验证码

curl -X POST http://localhost:6170/api/v1/auth/sms/verify \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "13800138000",
    "countryCode": "+86",
    "code": "123456",
    "purpose": "login"
  }'

预期响应:

{
  "code": 200,
  "message": "Success",
  "data": {
    "success": true
  }
}

生产环境配置

1. 阿里云短信服务配置

1.1 创建短信签名

  1. 登录阿里云控制台
  2. 进入短信服务 → 国内消息 → 签名管理
  3. 添加签名:道研组
  4. 等待审核通过

1.2 创建短信模板

  1. 进入短信服务 → 国内消息 → 模板管理
  2. 添加模板:
    • 模板名称:验证码通知
    • 模板内容:您的验证码是${code},有效期10分钟,请勿泄露。
    • 模板类型:验证码
  3. 等待审核通过
  4. 记录模板 CODE(如:SMS_123456789

1.3 获取 AccessKey

  1. 进入阿里云控制台 → AccessKey 管理
  2. 创建 AccessKey
  3. 记录 AccessKey ID 和 Secret(仅显示一次)

2. 更新生产环境变量

# 生产环境配置
SMS_TEST_MODE=False
SMS_ACCESS_KEY_ID=LTAI5tXXXXXXXXXXXXXX
SMS_ACCESS_KEY_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx
SMS_SIGN_NAME=道研组
SMS_TEMPLATE_CODE=SMS_123456789

3. 配置 Celery 定时任务

编辑 server/app/tasks/celery_app.py,添加定时任务配置:

from celery.schedules import crontab

app.conf.beat_schedule = {
    # 清理过期短信验证码(每小时执行)
    'clean-expired-sms-codes': {
        'task': 'sms.clean_expired_codes',
        'schedule': crontab(minute=0),  # 每小时的第 0 分钟
    },
}

4. 重启服务

# 重启 API 服务
docker-compose restart api

# 重启 Celery Worker
docker-compose restart celery-worker

# 重启 Celery Beat
docker-compose restart celery-beat

故障排查

问题 1:短信发送失败

症状:API 返回 500 错误,日志显示"短信发送失败"

可能原因

  1. AccessKey 配置错误
  2. 短信签名或模板未审核通过
  3. 阿里云账户余额不足
  4. 网络连接问题

解决方案

# 1. 检查配置
cat .env | grep SMS

# 2. 检查阿里云控制台
# - 签名状态:已审核
# - 模板状态:已审核
# - 账户余额:充足

# 3. 测试网络连接
curl https://dysmsapi.aliyuncs.com/

# 4. 查看详细日志
docker-compose logs -f api | grep "短信"

问题 2:验证码验证失败

症状:输入正确的验证码仍然提示"验证码错误"

可能原因

  1. 验证码已过期(10分钟)
  2. 验证码已被使用
  3. 手机号或国家区号不匹配

解决方案

-- 查询验证码记录
SELECT 
    id,
    phone,
    country_code,
    code,
    purpose,
    expires_at,
    verified,
    created_at
FROM sms_verification_codes
WHERE phone = '13800138000'
ORDER BY created_at DESC
LIMIT 5;

问题 3:触发限流

症状:API 返回 429 错误,提示"发送过于频繁"

可能原因

  1. 1分钟内发送超过 1 次(同手机号)
  2. 1小时内发送超过 5 次(同手机号)
  3. 1分钟内发送超过 3 次(同 IP)

解决方案

# 查看 Redis 限流记录
redis-cli

# 查看手机号限流
KEYS sms:phone:*

# 查看 IP 限流
KEYS sms:ip:*

# 清除特定限流(仅测试环境)
DEL sms:phone:+86:13800138000:1min
DEL sms:phone:+86:13800138000:1hour

问题 4:定时任务未执行

症状:过期验证码未被清理

可能原因

  1. Celery Beat 未启动
  2. 定时任务配置错误

解决方案

# 检查 Celery Beat 状态
docker-compose ps celery-beat

# 查看 Celery Beat 日志
docker-compose logs -f celery-beat

# 手动触发清理任务
docker-compose exec celery-worker celery -A app.tasks.celery_app call sms.clean_expired_codes

监控建议

1. 关键指标

在生产环境中,建议监控以下指标:

指标 说明 告警阈值
发送成功率 短信发送成功/总发送次数 < 95%
验证成功率 验证码验证成功/总验证次数 < 80%
限流触发次数 防刷机制触发次数 > 100/小时
平均响应时间 API 响应时间 > 2秒

2. 日志监控

关键日志关键字:

# 发送成功
grep "验证码已发送" api.log

# 验证成功
grep "验证码验证成功" api.log

# 发送失败
grep "短信发送失败" api.log

# 触发限流
grep "发送过于频繁" api.log

相关文档


文档版本:v1.0
最后更新:2026-01-27