Django集成Twilio无法发送OTP的问题排查求助
Django集成Twilio无法发送OTP的问题排查求助
我正在自己的Django项目里用Twilio实现OTP短信验证功能,已经成功申请到了Twilio的专用手机号,但现在遇到了一个棘手的问题:OTP短信始终无法发送到用户的手机上。下面是我所有的配置和代码细节,麻烦各位帮忙看看哪里出问题了!
我的实现代码细节
1. views.py 核心代码
def send_otp_view(request): if request.method == "POST": data = json.loads(request.body) phone_number = data.get('phone_number') # 生成6位随机OTP otp = random.randint(100000, 999999) # 调用Twilio发送OTP try: client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) message = client.messages.create( body=f"Your OTP is {otp}. Please use this to verify your number.", from_=settings.TWILIO_PHONE_NUMBER, to=phone_number ) # 将OTP和手机号存入Session request.session['otp'] = otp request.session['phone_number'] = phone_number return JsonResponse({'status': 'success', 'otp': otp}) # 返回OTP用于前端验证 except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}) return JsonResponse({'status': 'error', 'message': 'Invalid request'}) def address_view(request): if request.user.is_authenticated: user_addresses = Address.objects.filter(user=request.user) if request.method == "POST": # 获取表单提交的OTP entered_otp = request.POST.get("otp") # 验证OTP是否正确 if entered_otp == str(request.session.get('otp')): # OTP正确,保存地址信息 mobile = request.POST.get("mobile") email = request.POST.get("email") pin = request.POST.get("pin") region = request.POST.get("region") address = request.POST.get("address") landmark = request.POST.get("landmark") name = request.POST.get("name") new_address = Address.objects.create( user=request.user, mobile=mobile, email=email, pin=pin, region=region, address=address, landmark=landmark, name=name, ) messages.success(request, "Address Added Successfully.") return redirect("core:address") else: messages.error(request, "Invalid OTP. Please try again.") return redirect("core:address") context = { "user_addresses": user_addresses, } return render(request, 'others/address-book.html', context) else: print("User is not authenticated") return redirect("core:login")
2. HTML 表单代码
<div class="gl-inline"> <div class="u-s-m-b-30"> <label class="gl-label" for="address-phone">PHONE *</label> <input class="input-text input-text--primary-style" type="text" id="address-phone" name="mobile" placeholder="Enter 10-digit phone number" oninput="validatePhoneNumber()" maxlength="10"> <button type="button" id="send-otp-btn" style="display:none;" onclick="sendOTP()">Send OTP</button> </div> <div id="otp-box" style="display: none;" class="u-s-m-b-30"> <label class="gl-label" for="otp-input">ENTER OTP *</label> <input class="input-text input-text--primary-style" type="text" id="otp-input" name="otp" placeholder="Enter OTP" maxlength="6" oninput="validateOTP()"> <span id="otp-feedback" style="display: none; font-size: 14px;"></span> </div> <div class="u-s-m-b-30"> <label class="gl-label" for="address-street">STREET ADDRESS *</label> <input class="input-text input-text--primary-style" type="text" id="address-street" placeholder="House Name and Street" name="address"> </div> </div>
3. Twilio 配置 (settings.py)
TWILIO_ACCOUNT_SID = 'YOUR_ACCOUNT_SID' TWILIO_AUTH_TOKEN = 'YOUR_AUTH_TOKEN' TWILIO_PHONE_NUMBER = '+1234567890' # 带国家码的Twilio号码
4. 前端验证 JavaScript 代码
console.log("OTP"); let sentOTP = null; // 存储后端返回的OTP function validatePhoneNumber() { const phoneInput = document.getElementById('address-phone'); const otpBox = document.getElementById('otp-box'); const sendOtpBtn = document.getElementById('send-otp-btn'); // 手机号长度为10位时显示OTP输入框和发送按钮 if (phoneInput.value.length === 10) { otpBox.style.display = 'block'; sendOtpBtn.style.display = 'inline-block'; } else { otpBox.style.display = 'none'; sendOtpBtn.style.display = 'none'; } } function sendOTP() { const phoneNumber = document.getElementById('address-phone').value; // 发送AJAX请求到后端获取并发送OTP fetch('/send-otp/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') // 处理CSRF验证 }, body: JSON.stringify({ phone_number: phoneNumber }) }) .then(response => response.json()) .then(data => { if (data.status === 'success') { sentOTP = data.otp; // 保存OTP用于前端预验证 console.log("OTP sent successfully"); } else { alert("Error sending OTP"); } }) .catch(error => { console.error('Error:', error); alert('Failed to send OTP'); }); } function validateOTP() { const otpInput = document.getElementById('otp-input'); const feedback = document.getElementById('otp-feedback'); // 前端预验证OTP是否正确 if (otpInput.value === sentOTP) { feedback.style.display = 'block'; feedback.style.color = 'green'; feedback.textContent = 'OTP is correct!'; } else if (otpInput.value.length === sentOTP.length) { feedback.style.display = 'block'; feedback.style.color = 'red'; feedback.textContent = 'Incorrect OTP, please try again.'; } else { feedback.style.display = 'none'; // 输入未完成时隐藏提示 } } // 从Cookie中获取CSRF Token的工具函数 function getCookie(name) { const cookieValue = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)'); return cookieValue ? cookieValue.pop() : ''; }
我遇到的具体问题
- 表单能正确提交手机号,POST请求也能正常到达Django的
send_otp_view视图 - 代码走到了Twilio的
client.messages.create调用逻辑,但就是没有短信发送到目标手机 - Django日志里只看到一条模糊的错误:
Error sending OTP: TwilioRestException: [Error message here](具体错误内容没显示全)
我已经尝试过的排查步骤
- 反复核对了Twilio的Account SID、Auth Token和手机号,确认都是正确的
- 确保接收手机号是标准E.164格式(比如+86开头的国内手机号)
- 确认Twilio试用账号已经在控制台验证过这个接收手机号
- 去Twilio的消息日志里查,完全找不到这条请求的记录
- 用独立Python脚本测试Twilio功能是正常的(脚本如下):
from twilio.rest import Client client = Client('YOUR_ACCOUNT_SID', 'YOUR_AUTH_TOKEN') message = client.messages.create( body="Test message", from_='+1234567890', to='+9876543210' ) print(message.sid)
期望行为
用户输入的手机号能正常收到OTP验证短信
我的问题
到底哪里出问题了?是Twilio的账号设置有坑,还是Django的配置或者代码有遗漏?求各位大佬给点排查方向或者解决方案!
补充说明:
- 我用的是Twilio免费试用账号
- 接收方手机号已经在Twilio控制台完成验证
- 我的开发环境没有网络或防火墙限制
备注:内容来源于stack exchange,提问作者Google User
相关产品推荐
相关产品推荐

