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
相关产品推荐
相关产品推荐

