Node.js + Mongoose按分类获取博客文章?路由冲突问题求助
Node.js博客路由冲突问题解决
问题现象
- 初始路由顺序下,单篇文章路由
/:slug正常工作,但点击分类链接会跳转到首页;将分类路由移至单篇文章路由上方后,分类页面正常,但单篇文章页面显示分类列表内容。 - 将单篇文章路由修改为
/:category_slug/:slug后,分类和单篇文章功能恢复正常,但编辑页面/edit/:id无法访问。
原代码示例
// blog article page articleRouter.get('/:slug', async (req, res) => { const article = await Article.findOne({ slug: req.params.slug }); if(article == null) res.redirect('/'); res.render('blog/show', { article: article }); }); // get blog article category page articleRouter.get('/:category_slug', async (req, res) => { const articles = await Article.find({ category_slug: req.params.category_slug }).sort( { createdAt: 'descending' }); res.render('blog/category', { articles: articles }); }); // edit blog article page articleRouter.get('/edit/:id', async (req, res) => { const article = await Article.findById(req.params.id) res.render('blog/edit', { article: article }); });
问题原因
- 单参数路由冲突:
/:slug和/:category_slug都是单参数动态路由,Express路由匹配是从上到下执行的。初始顺序下,分类链接的参数会被当作文章slug查询,查不到就跳首页;调整顺序后,文章slug会被当作分类slug查询,返回分类列表。 - 编辑路由被拦截:修改为
/:category_slug/:slug双参数路由后,访问/edit/xxx时,edit会被解析为category_slug,xxx被解析为slug,触发单篇文章路由逻辑,因查不到对应文章而跳转到首页,导致编辑页面无法访问。
解决方案
方案1:给分类路由添加固定前缀(推荐)
通过添加/category前缀区分分类路由和其他动态路由,同时将编辑路由放在最前面,避免被动态参数路由匹配:
// 编辑页面路由:优先匹配固定前缀路由 articleRouter.get('/edit/:id', async (req, res) => { const article = await Article.findById(req.params.id) res.render('blog/edit', { article: article }); }); // 单篇文章路由 articleRouter.get('/:slug', async (req, res) => { const article = await Article.findOne({ slug: req.params.slug }); if(article == null) res.redirect('/'); res.render('blog/show', { article: article }); }); // 分类页面路由:添加/category前缀避免冲突 articleRouter.get('/category/:category_slug', async (req, res) => { const articles = await Article.find({ category_slug: req.params.category_slug }).sort( { createdAt: 'descending' }); res.render('blog/category', { articles: articles }); });
方案2:调整路由顺序并优化匹配逻辑
如果不想修改分类路由URL,需将编辑路由和分类路由放在单篇文章路由前面,同时在分类路由中增加判断逻辑,兜底处理文章slug的情况:
// 编辑页面路由:优先匹配 articleRouter.get('/edit/:id', async (req, res) => { const article = await Article.findById(req.params.id) res.render('blog/edit', { article: article }); }); // 分类页面路由:其次匹配,无对应分类则尝试查询文章 articleRouter.get('/:category_slug', async (req, res) => { const articles = await Article.find({ category_slug: req.params.category_slug }).sort( { createdAt: 'descending' }); if(articles.length === 0) { const article = await Article.findOne({ slug: req.params.category_slug }); if(article) { return res.render('blog/show', { article: article }); } return res.redirect('/'); } res.render('blog/category', { articles: articles }); });
内容的提问来源于stack exchange,提问作者jag6
相关产品推荐
相关产品推荐

