You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express路由调用async控制器报Route.post()需回调却得到Promise错误如何解决

报错原因

你当前的代码存在两个核心问题直接触发报错:

  1. wrapRoute没有接收要包装的控制器函数fn作为入参,逻辑本身不完整
  2. wrapRoute被定义为async函数,你直接调用wrapRoute(async (req,res)=>{})后返回的是Promise对象,而非Express路由要求的回调函数,因此触发Route.post() requires a callback function but got a [object Promise]报错。

修复方案

第一步:修正wrapRoute的实现

将wrapRoute改造为高阶函数,接收目标控制器函数作为入参,返回符合Express要求的中间件回调函数:

// 调整为接收fn作为参数,返回async中间件函数
const wrapRoute = (fn) => async (req, res, next) => {
  try {
      await fn(req, res, next)
  } catch (e) {
      next(e)
  }
}

第二步:补充遗漏的依赖引入

你当前EmailLogin.js里缺少必要依赖的引入,修复完路由问题后运行也会报错,在文件顶部补充对应引入即可:

const axios = require('axios');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const Users = require('../models/Users'); // 替换为你自己的User模型实际路径
const env = require('../config/env'); // 替换为你自己的环境变量配置实际路径

第三步:挂载全局错误处理中间件

你定义的errorHandler当前没有挂载到Express实例上,捕获的异常无法正常处理,调整App.js代码:

var express = require("express");
var app = express();
const { errorHandler } = require('./controllers/EmailLogin'); // 替换为对应实际路径
const Router = require('./routes/Router');

app.use('/', Router); 
// 全局错误处理中间件必须放在所有路由挂载之后
app.use(errorHandler);

app.listen(3000, function() {
  console.log('listening on 3000');
});

同时在EmailLogin.js里导出errorHandler:

module.exports = {EmailLogin, errorHandler};

常见疑问解答

Express原生不支持直接传入Promise作为路由处理函数,必须传入可调用的函数。你可以通过上述高阶函数包装的方式,让async函数(执行后返回Promise)作为路由处理函数使用,所有异步抛出的异常都会被wrapRoute捕获后传递给全局错误中间件处理,不需要每个控制器单独编写try catch逻辑。

可选优化:统一异步写法避免回调嵌套

你当前代码同时混用了await、then、回调函数三种异步写法,容易出现回调内异常无法被外层捕获的问题,建议统一用async/await改写控制器逻辑:

const EmailLogin = wrapRoute(async (req, res) => {
  const errors =  validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(422).json({ errors: errors.array() });
  }
  const gtoken = req.body.gtoken;
  const gSecretKey = env.secret_key;
  if (!gtoken) throw new Error('no token')

  const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${gSecretKey}&response=${gtoken}`
  const {data: gVerifyData} = await axios.post(captchaURL, {}, {
    headers: {ContentType: 'application/x-www-form-urlencoded'},
  })
  if (!gVerifyData.success) {
    return res.status(500).send('bot');
  }
  const user = await Users.findOne({'email': req.body.email}).select('+hashPassword +status')
  if (!user) {
    return res.send("wrong-info");
  }
  const validPassword = bcrypt.compareSync(req.body.password, user.hashPassword);
  if (!validPassword || user.status !== "active"){
    return res.send("wrong-info");
  }
  const token = jwt.sign({ id: user._id }, env.jwtsecret, { expiresIn: "168h" });
  res.status(200).send({ token: token, user });
});

内容的提问来源于stack exchange,提问作者turkdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 05:57:00