使用Twilio与Django 1.8.2连续发送多条SMS时遇到的问题
解决Django 1.8.2 + Twilio同一函数内多次发送短信的问题
我之前帮朋友排查过类似的问题,结合你的描述来看,核心矛盾就是同一函数内多次调用短信发送会报错,但拆分后同步执行又会导致页面加载超时,咱们来一步步解决:
先分析可能的报错原因
你没贴具体的错误信息,但根据Twilio + Django的常见问题,大概率是这两个原因:
- 每次调用发送函数都新建Twilio客户端实例,重复创建HTTP连接导致资源冲突
- 同步调用Twilio API时,单次请求内多次调用触发了Twilio的API频率限制,或者Django请求周期内的资源阻塞
解决方案一:复用Twilio客户端实例
很多人会习惯性地在发送函数里每次都新建Client,比如这样:
# 错误示例:每次调用都新建客户端 def send_sms(to, body): client = Client('你的account_sid', '你的auth_token') client.messages.create(body=body, from_='你的Twilio号码', to=to)
这种写法在单次调用时没问题,但多次调用会重复创建连接,容易出问题。咱们改成全局复用客户端:
# 在模块顶部初始化一次客户端 from twilio.rest import Client TWILIO_ACCOUNT_SID = '你的account_sid' TWILIO_AUTH_TOKEN = '你的auth_token' TWILIO_FROM_NUMBER = '你的Twilio号码' # 全局复用这个客户端实例 twilio_client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN) def send_sms(to, body): # 直接用全局客户端发送 twilio_client.messages.create( body=body, from_=TWILIO_FROM_NUMBER, to=to )
这样同一函数内多次调用send_sms时,复用同一个HTTP连接,大概率能解决报错问题。
解决方案二:异步发送短信,彻底解决页面超时问题
就算解决了多次调用的报错,同步发送还是会让页面卡很久——用户肯定不会等60秒。这时候咱们用Celery把短信发送放到后台异步执行,步骤如下:
1. 安装依赖(针对Django 1.8.2)
pip install celery==3.1.25 redis==2.10.6
选Celery 3.x是因为它和Django 1.8.2兼容性更好,Redis作为消息队列。
2. 配置Celery和Django集成
在你的Django项目根目录创建celery.py:
import os from celery import Celery # 设置Django环境变量 os.environ.setdefault('DJANGO_SETTINGS_MODULE', '你的项目名.settings') app = Celery('你的项目名') app.config_from_object('django.conf:settings') # 自动发现tasks.py里的任务 app.autodiscover_tasks()
然后在项目的__init__.py里添加:
from .celery import app as celery_app
3. 把短信发送改成异步任务
在你的app下创建tasks.py:
from celery import shared_task from twilio.rest import Client TWILIO_ACCOUNT_SID = '你的account_sid' TWILIO_AUTH_TOKEN = '你的auth_token' TWILIO_FROM_NUMBER = '你的Twilio号码' twilio_client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN) @shared_task def send_sms_task(to, body): twilio_client.messages.create( body=body, from_=TWILIO_FROM_NUMBER, to=to )
4. 在视图里调用异步任务
from django.http import HttpResponse from .tasks import send_sms_task def your_view(request): # 用delay()把任务丢到后台执行,立即返回响应 send_sms_task.delay('目标号码1', '第一条短信内容') send_sms_task.delay('目标号码2', '第二条短信内容') return HttpResponse('短信已提交发送,请稍后查看')
这样用户点击后页面瞬间响应,短信在后台慢慢发送,完全不会有超时的问题。
额外注意事项
- 记得检查Twilio的控制台,看看有没有API调用失败的记录,确认是不是频率限制的问题
- 如果不用Celery,也可以用Django的
Thread来开线程发送,但Celery是更规范的异步方案
内容的提问来源于stack exchange,提问作者Outsider
相关产品推荐
相关产品推荐

