Express中间件执行顺序异常:路由处理函数提前触发求助
Express中间件执行顺序异常:路由处理函数先于authenticatedUser中间件执行
我正在使用firebase-admin为Express后端服务器做身份认证,接口由React应用触发。预期中间件按getUserToken > authenticatedUser > postNewWarehouse的顺序执行,但实际输出显示路由处理函数postNewWarehouse在authenticatedUser中间件之前就触发了。
服务器代码
index.js
const express = require('express'); const cors = require("cors"); const jwt = require("jsonwebtoken"); const mongoose = require('mongoose'); require("dotenv").config(); const app = express(); const port = process.env.PORT || 5000; app.use(cors()); app.use(express.json()); const inventoryRoutes = require('./routes/inventoryRoutes'); //global middleware app.use((req, res, next) => { console.log(req.path, req.method); next(); }) //routes app.use('/api',inventoryRoutes); //welcome route app.get("/", (req, res) => { res.send("Hello"); }) //Database connection mongoose.connect(`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@cluster0.wbmcg.mongodb.net/skus?retryWrites=true&w=majority`, { dbName: "inventoryDB" }) .then(() => { console.log('connected to db'); }) .catch((error) => { console.log(error); }) //start Server app.listen(port, () => { console.log("Inventory server is running on port ", port); })
inventoryRoutes.js
const express = require('express'); const router = express.Router(); const { getUserToken, authenticatedUser } = require('../middleware/userAuthMiddleware') //create a warehouse router.post('/createwarehouse', getUserToken, authenticatedUser, postNewWarehouse) module.exports = router
userAuthMiddleware.js
const admin = require('../firebase-config') const getUserToken = async (req, res, next) => { const token = req.headers.authorization.split(' ')[1]; const decodedValue = await admin.auth().verifyIdToken(token); console.log("at getUserToken middleware, logged in user email is -> ", decodedValue.email); req.email = decodedValue.email; next() } const authenticatedUser = ( req, res, next ) => { admin.auth().listUsers() .then(response => { connectedUser = req.email; console.log("at authenticatedUser middleware, logged in user email is -> ",connectedUser); const user = []; response.users.forEach((userRecord) => { user.push(userRecord.toJSON().email) }) // console.log(user); const email = user.find(newuser => newuser === connectedUser) console.log(email, " -> email is found in user list"); }) next() } module.exports = { authenticatedUser, getUserToken }
实际控制台输出
/api/createwarehouse POST at getUserToken middleware, logged in user email is -> hello1@gello.com from the main function of the route -> { name: 'ertyyju', space: '23456', description: 'New warehouseerty' } at authenticatedUser middleware, logged in user email is -> hello1@gello.com hello1@gello.com -> email is found in user list
尝试过的解决方式
我试过把前两个中间件合并成数组,但问题依旧:
const middlewares = [getUserToken, authenticatedUser] router.post('/createwarehouse', middlewares, postNewWarehouse)
请问为什么路由处理函数会在authenticatedUser中间件之前执行?
问题原因
问题出在authenticatedUser中间件的异步操作处理上:admin.auth().listUsers()是异步Promise操作,你在调用这个方法后立刻执行了next(),没有等待异步逻辑完成。这导致Express直接跳过中间件的剩余异步代码,先进入下一个处理环节(postNewWarehouse),等listUsers()的Promise完成后才会执行then回调里的日志代码,所以输出顺序混乱。
解决方法
把next()放到异步操作的回调末尾,确保只有在身份验证逻辑完成后,才让请求进入下一个处理步骤:
回调写法修改
const authenticatedUser = ( req, res, next ) => { admin.auth().listUsers() .then(response => { connectedUser = req.email; console.log("at authenticatedUser middleware, logged in user email is -> ",connectedUser); const user = []; response.users.forEach((userRecord) => { user.push(userRecord.toJSON().email) }) const email = user.find(newuser => newuser === connectedUser) console.log(email, " -> email is found in user list"); // 异步操作完成后再调用next() next() }) // 新增错误处理,避免请求挂起 .catch(error => { console.error('获取用户列表失败:', error); res.status(500).json({ error: '身份验证失败' }); }) }
Async/Await写法(更清晰)
const authenticatedUser = async ( req, res, next ) => { try { const response = await admin.auth().listUsers(); connectedUser = req.email; console.log("at authenticatedUser middleware, logged in user email is -> ",connectedUser); const user = response.users.map(userRecord => userRecord.toJSON().email); const email = user.find(newuser => newuser === connectedUser); console.log(email, " -> email is found in user list"); next(); } catch (error) { console.error('获取用户列表失败:', error); res.status(500).json({ error: '身份验证失败' }); } }
修改后,中间件会先完成异步身份验证逻辑,再触发后续的路由处理函数,执行顺序就能符合预期。
内容的提问来源于stack exchange,提问作者Ahsan
相关产品推荐
相关产品推荐

