Express中无法从URL获取id参数问题求助
问题
在Express中尝试从/listings/:id路径提取id参数时,req.params.id始终无法获取到值(返回undefined)。请求路由经过server.js → getListingRoutes.js → getListing.js三层结构,使用Postman发送请求http://localhost:3500/listings/a7609764-646d-48bd-8b60-fc5d0c83c4e8时,控制器中始终提示“Listing ID required”。尝试修改getListingRoutes.js中的router.route()路径,但除了/之外的设置都会导致无法调用控制器。
相关代码
server.js
require('dotenv').config() const express = require('express') const app = express() const path = require('path') const PORT = process.env.PORT || 3500 const { logger, logEvents } = require('./middleware/logger') const errorHandler = require('./middleware/errorHandler') const cookieParser = require('cookie-parser') const cors = require('cors') const corsOptions = require('./config/corsOptions') const connectDB = require('./config/dbConn') const mongoose = require('mongoose') app.use(logger) connectDB() app.use(cors(corsOptions)) app.use(express.json()) app.use(cookieParser()) app.use('/listings/:id', require('./routes/getListingRoutes')) app.use('/', express.static(path.join(__dirname, '/public'))) app.use('/', require('./routes/root')) app.use('/listings', require('./routes/getAllListingsRoutes')) // Working app.use('/new-listing', require('./routes/createNewListingRoutes')) // Working app.use('/edit-listing/:id', require('./routes/updateListingRoutes')) // app.get('/listings/:id', (req, res) => { // console.log(req.params.id) // }) // Getting the params here. app.use('/listings/:id/add-view', require('./routes/addViewToListingRoutes')) app.use('/listings/user/:userId', require('./routes/getUserListingsRoutes')) app.use('/my-listings', require('./routes/getUserListingsRoutes')) app.all('*', (req, res) => { res.status(404) if (req.accepts('html')) { res.sendFile(path.join(__dirname, 'views', '404.html')) } else if (req.accepts('json')) { res.json({ message: '404 Not Found'}) } else { res.type('txt').send('404 Not Found') } }) app.use(errorHandler) mongoose.connection.once('open', () => { console.log('Connected to MongoDB') app.listen(PORT, () => console.log(`Server running on port ${PORT}`)) }) mongoose.connection.on('error', err => { console.log(err) logEvents(`${err.no}: ${err.code}\t${err.syscall}\t${err.hostname}`, 'mongoErrLog.log') })
getListingRoutes.js
const express = require('express') const router = express.Router() const getListingController = require('../controllers/getListing') router.use(function(req, res, next) { console.log(req.params.id, "@", Date.now()); next(); }); router.route("/") .get(getListingController.getListingRoute) module.exports = router
getListing.js
const User = require('../models/User') const asyncHandler = require('express-async-handler') const path = require('path') // @desc GET specific listing // @route GET /listings/:id // @access Public const getListingRoute = asyncHandler(async (req, res) => { console.log("Reached getListing.js") const id = req.params.id console.log(req.path) if (!id) { return res.status(400).json({ message: 'Listing ID required' }) } const listing = await User.findById(id).exec() if (!listing) { return res.status(400).json({ message: 'Listing not found!' }) } console.log(listing) res.json(listing) }) module.exports = {getListingRoute}
解决方案
1. 启用子路由的参数继承
问题核心在于:当通过app.use('/listings/:id', router)挂载子路由时,Express的Router默认不会将父路由的URL参数(比如:id)传递给子路由。需要在创建子路由时显式启用mergeParams选项,让子路由能够访问父路由的参数。
修改getListingRoutes.js中的Router创建代码:
// 启用mergeParams,允许子路由访问父路由的params const router = express.Router({ mergeParams: true })
2. 确认路由顺序(可选优化)
当前server.js中/listings/:id的路由挂载在/listings之前,这个顺序是正确的——因为Express会按从上到下的顺序匹配路由,如果/listings先挂载,会优先匹配所有以/listings开头的请求,导致/listings/:id永远无法被触发。保持当前顺序即可。
验证修改
重启服务后,再次用Postman发送请求http://localhost:3500/listings/a7609764-646d-48bd-8b60-fc5d0c83c4e8,此时req.params.id应该能正确获取到URL中的id值,控制器也能正常查询数据。
内容的提问来源于stack exchange,提问作者Prakhar Sharma

