Express.js 应用程序错误:类别名称被用作 post id

Express.js application bug: category name is taken for post id

我正在研究 blogging application (click the link to see the GitHub repo) with Express, EJS 和 MongoDB。

我有帖子,它们被分为类别,每个类别都有自己的集合。

我按类别过滤帖子:运动类别中的所有帖子显示在http://localhost:3000/sport旅游中的所有帖子] 类别显示在 http://localhost:3000/travel.

为此我引入了路线 router.get('/:catname', postsController.getPostsByCategory);:

const express = require('express');
const postsController = require('../../controllers/front-end/posts');

// Express router
const router = express.Router();

// Get Posts
router.get('/', postsController.getPosts);

// Get Posts by Category
router.get('/:catname', postsController.getPostsByCategory);

// Get Single Post
router.get('/:id', postsController.getSinglePost);

module.exports = router;

类别确实按类别过滤,但是 router.get('/:catname', postsController.getPostsByCategory);和 router.get('/:id', postsController.getSinglePost); 之间存在冲突,因此 不再显示单个帖子

那是因为帖子ID被用于类别路由。

在控制器中我有两种方法 getPostsByCategorygetSinglePost:

exports.getPostsByCategory = async (req, res, next) => {

    function titleize(slug) {
        var words = slug.split("-");
        return words.map(function(word) {
            return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
        }).join(' ');
    }

    const postCategory = new RegExp(titleize(req.params.catname),"ig");

    const singleCategory = await Category.findOne({cat_name:postCategory})

    const posts = await Post.find({ category : singleCategory }, (err, posts) => {
        if (err) {
            console.log('Error: ', err);
        } else {
            res.render('default/index', {
                moment: moment,
                layout: 'default/layout',
                website_name: 'MEAN Blog',
                page_heading: 'XPress News',
                page_subheading: 'A MEAN Stack Blogging Application',
                posts: posts.reverse(),
            });
        }
    }).populate('category');
};

exports.getSinglePost = (req, res, next) => {
    let id = req.params.id;
    if (id.match(/^[0-9a-fA-F]{24}$/)) {
        Post.findById(id, function(err, post) {
            if (err) {
                console.log('Error: ', err);
            } else {
                res.render('default/singlepost', {
                    layout: 'default/layout',
                    website_name: 'MEAN Blog',
                    post: post
                });
            }
        });
    }
};

在我拥有的(所有)帖子的视图中:

<p class="post-meta">Posted in <a href="/<%= post.category.cat_name.replace(/\s+/g, '-').toLowerCase(); %>"><%= post.category.cat_name %></a>, on <%= moment(post.created_at).format( 'MMM-DD-YYYY') %></p>

我想解决此问题的方式是保持按类别显示帖子的 URL 的模式 http://localhost:3000/category-name

我怎样才能做到这一点?

其实这两条路线是一样的:

// Get Posts by Category
router.get('/:catname', postsController.getPostsByCategory);

// Get Single Post
router.get('/:id', postsController.getSinglePost);

我建议创建不同的路线,例如:

// Get Posts by Category
router.get('/category/:catname', postsController.getPostsByCategory);

// Get Single Post
router.get('/post/:id', postsController.getSinglePost);

如果按类别保持单个 post 和 post 的模式 http://localhost:3000/:param 对您很重要,您可以只使用一种路由方法处理两个请求

// This will handle Get requests both for Posts by Category and single Post
router.get('/:param', (req, res, next) => {
    // If :param is Mongo ObjectId call the getSinglePost method.
    if (req.params.param.match(/^[0-9a-fA-F]{24}$/)) {
        postsController.getSinglePost(req, res, next);
    } 
    else {
        postsController.getPostsByCategory(req, res, next);
    }
});

我刚刚添加了一个中间件,它检查请求参数。如果它是 ObjectId 类型,则调用 getSinglePost 方法,否则调用 getPostsByCategory 方法。

您唯一需要做的就是在 postsController 文件的两个方法中用 req.params.param 替换 req.params.catnamereq.params.id

你也可以去掉getSinglePost方法中的匹配检查,因为它是在路由文件中实现的。