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

Express搭建NodeJS服务器报错:Route.post()需回调函数却获undefined

问题根源:循环引用与导出顺序错误

你的错误Error: Route.post() requires a callback function but got a [object Undefined]本质是循环引用+导出顺序错误导致authenticateToken等变量未被正确传递到account.js:

  • 循环引用链:server.js导入accountRoutes,而account.js又导入server.js的authenticateToken等变量
  • 导出顺序错误:server.js中先执行module.exports = pool,后续的导出会覆盖之前的内容,但导入accountRoutes时,authenticateToken还未定义,此时account.js拿到的是最初导出的pool对象,而非包含authenticateToken的对象,导致authenticateToken在account.js中为undefined,触发路由回调错误。

修复步骤

步骤1:拆分公共依赖,彻底解决循环引用

在根目录新建config.js,存放无需关联Express的公共变量:

const dotenv = require('dotenv');
const fs = require('fs');
const { Pool } = require('pg');

dotenv.config();
const dbConfig = JSON.parse(fs.readFileSync('db_config.json'));
const pool = new Pool(dbConfig);
const JWT_SECRET = process.env.JWT_SECRET;
const saltRounds = 10;

module.exports = { pool, JWT_SECRET, saltRounds };

步骤2:调整server.js的导出与导入顺序

// 导入必要模块
const cors = require('cors');
const express = require('express');
const { createServer } = require('http');
const { join } = require('path');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
// 导入公共配置
const { pool, JWT_SECRET, saltRounds } = require('./config');

// 初始化Express应用
const app = express();
app.use(cors());
const server = createServer(app);
const io = require('socket.io')(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
    transports: ['websocket', 'polling'],
    allowedHeaders: ['Access-Control-Allow-Origin'],
    credentials: true
  },
  allowEIO3: true,
  cookie: {
    name: "io",
    path: "/",
    httpOnly: true,
    sameSite: "lax"
  }
});
io.attach(server);
server.listen(3000, () => {
  console.log('server running at http://localhost:3000');
});

// 存储会话ID
const accounts = {};

// 中间件配置
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));

// 先定义JWT中间件,再导入路由
const authenticateToken = (req, res, next) => {
  // 加可选链避免请求头无authorization时报错
  var token = req.headers.authorization?.split(' ')[1];
  if (token) {
    return jwt.verify(token, JWT_SECRET, function (err, decoded) {
      if (err) {
        return res.json({
          success: false,
          message: "Failed to authenticate token.",
        });
      }
      req.user = decoded;
      return next();
    });
  }
  // 替换res.unauthorized()为Express标准401响应
  return res.status(401).json({ success: false, message: "No token provided." });
};

// 导入并挂载account路由
const accountRoutes = require('./routes/account');
app.use('/account', accountRoutes);

// 根路由与认证路由
app.get('/', (req, res, next) => {
  res.sendFile(join(__dirname + '/public/index.html'));
});

app.get('/auth', authenticateToken, (req, res) => {
  res.json({ authenticated: true, user: req.user });
});

app.post('/', async (req, res) => {});

// 导出需要的变量
module.exports = { authenticateToken, pool, JWT_SECRET, saltRounds };

步骤3:修改account.js的导入来源

const { authenticateToken } = require('../server');
const { pool, JWT_SECRET, saltRounds } = require('../config');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();

// 登出路由
router.post('/logout', authenticateToken, async (req, res) => {
  // 你的业务代码
});

// 注册路由
router.post('/register', async (req, res) => {
  // 你的业务代码
});

// 登录路由
router.post('/login', async (req, res) => {
  // 你的业务代码
});

// 删除账号路由
router.post('/delete', authenticateToken, async (req, res) => {
  // 你的业务代码
});

module.exports = router;

额外修复说明
  • 替换了非Express内置的res.unauthorized(),改用标准的res.status(401)返回未授权响应
  • 在获取token时添加可选链?.,避免请求头无authorization字段时触发Cannot read properties of undefined错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:30:08