Twilio点击提交后无法处理手机号、发送验证码问题
问题原因
一共6个核心错误,直接导致功能完全失效:
- 前后端接口路径不匹配:前端提交手机号时请求的接口地址是
/send-notification,但后端定义的发送验证码路由是/send-verification,请求直接返回404,前端判断response.ok为false,既不会触发验证码发送逻辑,也不会切换到验证码输入表单。 - 后端未定义Verify服务SID变量:两个Twilio接口中都使用了未声明的
verify变量,运行时会直接抛出引用错误,无法调用Twilio的短信服务。 - 后端发送验证码接口逻辑错误:接口没有等待Twilio接口返回结果就提前发送200状态码,既无法感知Twilio侧的报错(比如账号配置错误、手机号格式非法、余额不足),也可能因为异步时序问题导致请求失败。
- 前端验证码传参笔误:提交验证码时,传给后端的参数写的是
otp: top,top是浏览器内置的全局窗口对象,不是用户输入的验证码值,后端拿不到正确验证码永远校验失败。 - 静态资源路径配置问题:后端配置的静态资源目录是
public文件夹,如果script.js放在views目录下,浏览器会加载不到JS文件,所有表单交互逻辑直接失效。 - 前端错误处理缺失:仅捕获了网络层错误,没有打印HTTP 4xx/5xx的错误信息,出问题时控制台无明确报错,难以定位问题。
修复步骤
1. 修正后端代码
打开index.js,做如下修改:
- 补充读取Twilio Verify服务SID的环境变量,确保
.env文件中已经配置了TWILIO_VERIFY_SERVICE_SID(值为Twilio控制台创建的Verify服务SID,VA开头) - 修正发送验证码接口的异步逻辑,等待Twilio返回结果后再给前端响应
- 保持后端路由路径不变,后续修改前端请求路径对齐即可
修正后的核心后端代码:
const express = require('express'); const path = require('path'); require('dotenv').config(); const client = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); // 补上Verify服务SID读取 const verify = process.env.TWILIO_VERIFY_SERVICE_SID; const app = express(); const port = process.env.PORT || 3000; app.use(express.static(__dirname + '/public')); app.use(express.urlencoded({extended: true})); app.use(express.json()); app.get('/', (req, res) => { res.sendFile(path.join(__dirname, '/views/index.html')); }); // 修正发送验证码接口逻辑 app.post('/send-verification', async (req, res) => { try { const verification = await client.verify.services(verify) .verifications .create({to: `+${req.body.phoneNumber}`, channel: 'sms'}); console.log('验证码发送状态:', verification.status); res.sendStatus(200); } catch (e) { console.log('发送验证码报错:', e); res.status(500).send(e.message); } }); app.post('/verify-otp', async (req, res) => { try { const check = await client.verify.services(verify) .verificationChecks .create({to: `+${req.body.phoneNumber}`, code: req.body.otp}); res.status(200).send(check); } catch (e) { console.log('校验验证码报错:', e); res.status(500).send(e.message); } }); app.listen(port, () => { console.log('Server started at http://localhost:' + port); });
2. 修正前端JS代码
打开script.js,做如下修改:
- 将提交手机号的请求路径从
/send-notification改为/send-verification,和后端路由对齐 - 修正验证码提交时的参数笔误,把
otp: top改为otp: otp - 补充基础错误提示,方便排查问题
- 将
script.js移动到项目根目录的public文件夹下,确保浏览器能正常加载静态资源
修正后的script.js代码:
const phoneForm = document.getElementById('phone-form'); const verifyForm = document.getElementById('verify-form'); const responseText = document.getElementById('response-text'); let phoneNumber; phoneForm.addEventListener('submit', async e => { e.preventDefault(); phoneNumber = document.getElementById('phone-number-input').value.trim(); if (!phoneNumber) { alert('请输入手机号'); return; } try { const response = await fetch('/send-verification', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({phoneNumber : phoneNumber }) }); if (!response.ok) { const errMsg = await response.text(); alert(`发送验证码失败:${errMsg}`); return; } phoneForm.style.display = 'none'; verifyForm.style.display = 'block'; } catch (e) { console.log('请求错误:', e); alert('网络请求失败,请检查服务是否启动'); } }); verifyForm.addEventListener('submit', async e => { e.preventDefault(); const otp = document.getElementById('otp-input').value.trim(); if (!otp) { alert('请输入验证码'); return; } const data = { phoneNumber: phoneNumber, otp: otp // 修正笔误,原来的top是错误值 }; try { const response = await fetch('/verify-otp', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(data) }); const check = await response.json(); if (!response.ok) { alert(`校验失败:${response.statusText}`); return; } responseText.innerHTML = check.status === 'approved' ? '验证成功' : '验证失败'; verifyForm.style.display = 'none'; responseText.style.display = 'block'; } catch (e) { console.log('校验请求错误:', e); alert('校验请求失败'); } });
3. 配置检查
修改完代码后,确认以下配置项正确:
.env文件中三个参数TWILIO_ACCOUNT_SID、TWILIO_AUTH_TOKEN、TWILIO_VERIFY_SERVICE_SID均为Twilio控制台复制的正确值,没有多余空格或拼写错误- 如果使用Twilio测试账号,需要将接收短信的手机号添加到测试账号的可信手机号列表中,否则无法收到验证码
- 输入手机号时需要带正确的国家码,比如中国大陆手机号是
86开头,格式为8613xxxxxxxxx,不需要手动加+,后端已经做了拼接
内容的提问来源于stack exchange,提问作者amoztar
相关产品推荐
相关产品推荐

