如何返回函数执行结果?实现Node.js两步验证码的前端页面输入
两步登录流程改造实现方案
你现有代码存在两个会导致流程跑不通的硬伤:
- 路由处理函数完全没有调用响应对象返回内容,前端发起的登录请求会一直挂起直到超时
- 登录SDK的2FA输入逻辑默认绑定了服务端命令行的stdin读取,没有做拦截,导致验证码输入只能在cmd完成
核心改造思路
因为整个登录流程是「提交账号密码→校验通过触发2FA要求→提交验证码→最终登录完成」的跨异步阶段流程,不需要在单个HTTP请求里等待全流程走完,只需要把每个阶段的状态通过接口返回给前端,拆分两次请求对接不同阶段的逻辑即可。
具体代码实现
1. 拦截SDK的默认命令行输码逻辑
首先在服务端维护几个临时变量,用来暂存当前登录流程的上下文,替代原来的cmd输入逻辑:
// 暂存当前待处理的2FA回调、当前登录流程的响应对象 let currentPending2FACallback = null let currentPasswordSubmitRes = null let currentLoginResultRes = null // 监听SDK触发的需要2FA验证码的事件 client.on('authCodeRequired', (codeSubmitCallback) => { // 把SDK的验证码提交回调暂存,替代之前的stdin手动输入 currentPending2FACallback = codeSubmitCallback // 如果当前还有等待的账号密码提交请求,直接返回需要2FA的状态 if (currentPasswordSubmitRes) { currentPasswordSubmitRes.json({ code: 1001, need2FA: true, msg: '请输入手机收到的5位两步验证码' }) currentPasswordSubmitRes = null } })
2. 改造原账号密码提交接口
app.post('/api/login/password', (request, response) => { // 暂存当前接口的响应对象,等2FA事件触发时可以直接返回状态 currentPasswordSubmitRes = response // 清空上一次的临时流程上下文 currentPending2FACallback = null client.logOn({ accountName: request.body.uName, password: request.body.uPassword, }) // 加15秒超时兜底,避免请求挂起 setTimeout(() => { if (currentPasswordSubmitRes) { currentPasswordSubmitRes.json({code: 500, msg: '登录请求超时,请重试'}) currentPasswordSubmitRes = null } }, 15000) })
3. 新增2FA验证码提交接口
专门接收前端传入的验证码,传给之前暂存的SDK回调,完成校验:
app.post('/api/login/2fa', (request, response) => { // 把当前响应对象暂存,等最终登录结果事件触发时返回 currentLoginResultRes = response if (!currentPending2FACallback) { return response.json({code: 400, msg: '无待校验的2FA流程,请重新提交账号密码'}) } const twoFactorCode = request.body.twoFactorCode // 把前端传的验证码提交给SDK,完全替代cmd手动输入的逻辑 currentPending2FACallback(twoFactorCode) })
4. 补全全流程结果的事件监听
把最终的登录成功/失败状态通过接口返回给前端:
// 登录成功事件 client.on('loggedOn', () => { console.log("Logged in"); // 登录成功后下发会话凭证给前端 if (currentLoginResultRes) { currentLoginResultRes.json({ code: 200, msg: '登录成功', // 这里可以下发JWT、Cookie等登录态凭证 token: '你的登录凭证内容' }) currentLoginResultRes = null } // 清空临时上下文 currentPending2FACallback = null }) // 登录失败事件(包含密码错误、2FA错误等所有异常) client.on('error', (err) => { console.log('登录失败', err) if (currentLoginResultRes) { currentLoginResultRes.json({ code: 500, msg: err.message || '登录失败,请检查输入' }) currentLoginResultRes = null } currentPending2FACallback = null })
前端交互配合
- 用户第一次提交账号密码时,如果接口返回
need2FA: true,直接在当前页面弹出2FA输入框,提示用户输入手机收到的验证码 - 用户输入验证码后,前端把码提交到
/api/login/2fa接口,等待接口返回最终的登录成功/失败结果
线上场景注意事项
- 上述代码是单用户测试场景的简化实现,如果是多用户并发的线上环境,不要用全局变量暂存流程上下文,需要用临时会话ID、用户提交的账号作为key,把每个登录流程的回调、响应对象做键值对存储隔离,避免不同用户的登录流程串数据
- 部分SDK可以在初始化或者调用
logOn时直接传配置禁用stdin输码逻辑,记得加上这个配置,避免服务端还是弹出cmd的输入提示 - 所有接口都要加超时兜底,避免因为SDK事件触发不及时导致HTTP连接一直占用
内容的提问来源于stack exchange,提问作者Cone
相关产品推荐
相关产品推荐

