短信定时发送必须由服务端实现,因前端无法持久运行且无权直连运营商网关;推荐方案为linux+crontab调用python短信脚本,或进阶使用apscheduler/celery实现任务持久化、重试与监控。

直接说结论:短信本身不能靠前端或本地定时器“自动发”,必须走服务端调度 + 短信网关 API;所谓“定时发送”,本质是「服务端在指定时间调用短信接口」。
为什么不能用 JavaScript 的 setInterval 或 cron 前端库
浏览器环境无法持久运行、页面关闭后任务立即终止、没有权限直连运营商网关。哪怕用 Node.js 本地跑 node-cron,机器重启或进程崩溃就失效,也不满足生产级可靠性。
- 真实场景需要:任务持久化(掉电不丢)、失败重试、执行记录、可监控
- 短信接口调用需携带鉴权密钥(
AppKey、Secret),绝不能暴露在前端代码里 - 运营商对单 IP/账号有频控(如 100 条/小时),服务端统一调度才能做限流和排队
推荐方案:Linux 服务器 + cron + 短信 SDK 脚本
适合中小项目,成本低、可控性强。核心是把“发短信”封装成一个可命令行执行的脚本,再由系统级定时任务触发。
- 用 Python 写一个
send_sms.py,调用阿里云/腾讯云 SDK(传入phone、template_id、template_param) - 确保脚本能独立运行:
python3 /path/to/send_sms.py --phone 13800138000 --param '{"code":"1234"}' - 编辑
crontab -e,添加一行:0 9 * * * /usr/bin/python3 /path/to/send_sms.py --phone 13800138000 --param '{"time":"09:00"}' >> /var/log/sms_cron.log 2>&1 - 注意路径用绝对路径,
PATH环境变量在 cron 中默认极简,必要时在 crontab 头部加PATH=/usr/local/bin:/usr/bin:/bin
更健壮的做法:用 APScheduler 或 Celery 做服务端任务队列
当需要动态增删任务、支持秒级精度、任务依赖或失败告警时,cron 就不够用了。
-
APScheduler(Python)适合单机部署:用SQLAlchemyJobStore把任务存进 MySQL,重启不丢;触发器选DateTrigger实现“只执行一次”的定时发送 -
Celery+Redis适合分布式:把发短信逻辑写成@shared_task,用apply_async(eta=xxx)设置未来执行时间 - 务必加异常捕获和日志:短信网关返回
InvalidPhoneNumber或TemplateParamError这类错误,得记录并告警,不能静默失败
真正难的不是“怎么设时间”,而是怎么保证「到了时间一定发出去、发失败了能感知、重复提交不重复发」——这些都得在服务端闭环,前端最多只负责「提交定时请求」这一步。










