You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MEAN栈Node.js博客:如何通过Slug而非ID实现资源路由?

解决MEAN栈中通过Slug获取资源的路由问题

问题背景

开发基于MEAN栈(使用Express Router)的Node.js博客,MongoDB中已存储字符串类型的slug字段,希望将原本通过:id调用的路由改为通过:slug调用,但修改后要么出现类型转换错误(无法找到ID),要么页面加载后无数据显示。

原可正常工作的ID路由:

router.get("/resources/:id", async (req, res) => {
    let foundResource = await Resources.findById(req.params.id);
        var metaTitle = foundResource.title;
        var metaDescription = foundResource.description;
        var metaKeywords = foundResource.keywords;
        var metaPath = foundResource.image;
    if (foundResource) {
        let allResources = await Resources.find({});
        res.render("insider/show", { Resources: allResources, resource: foundResource, metaTitle: metaTitle, metaDescription: metaDescription, metaKeywords:metaKeywords, metaPath:metaPath, page_name:'insider'});
    }

});

尝试修改的Slug路由(存在问题):

router.get("/resources/:slug", async (req, res) => {
    let foundResource = await Resources.find(req.params.slug);
        var metaTitle = foundResource.title;
        var metaDescription = foundResource.description;
        var metaKeywords = foundResource.keywords;
        var metaPath = foundResource.image;
    if (foundResource) {
        let allResources = await Resources.find({});
        res.render("insider/show", { Resources: allResources, resource: foundResource, metaTitle: metaTitle, metaDescription: metaDescription, metaKeywords:metaKeywords, metaPath:metaPath, page_name:'insider'});
    }
});

模型代码:

// schema setup
var mongoose = require("mongoose");

var resourceSchema = new mongoose.Schema({
    title: String,  
    image: String,
    url: String,
    resourceDetails: String,
    price: String,
    category: String,
    value: String,
    excerpt: String,
    slug: String,
    create: {type: Date, default: Date.now},
    author: {
      id: {
         type: mongoose.Schema.Types.ObjectId,
         ref: "User"
      },
      username: String
   },
});

module.exports = mongoose.model("Resources", resourceSchema);

错误原因分析

  1. 查询方法使用错误:Resources.find(req.params.slug) 写法错误,find方法需要传入查询条件对象(而非直接传字符串),且find返回匹配文档的数组,不是单个文档,应该用findOne获取单个匹配资源。
  2. 属性访问时机错误:如果foundResource为null(未找到资源),直接访问foundResource.title会抛出错误,必须先判断资源存在再赋值元数据。
  3. 缺少异常捕获:async函数未捕获Promise异常,一旦查询出错会导致服务器崩溃。

修正后的代码

1. 优化路由代码

router.get("/resources/:slug", async (req, res) => {
    try {
        // 通过slug查询单个资源,传入正确的查询条件对象
        let foundResource = await Resources.findOne({ slug: req.params.slug });
        
        if (!foundResource) {
            // 未找到资源时返回404提示
            return res.status(404).send("资源不存在");
        }

        // 找到资源后再赋值元数据
        var metaTitle = foundResource.title;
        var metaDescription = foundResource.description;
        var metaKeywords = foundResource.keywords;
        var metaPath = foundResource.image;

        let allResources = await Resources.find({});
        res.render("insider/show", { 
            Resources: allResources, 
            resource: foundResource, 
            metaTitle, 
            metaDescription, 
            metaKeywords, 
            metaPath, 
            page_name:'insider'
        });
    } catch (err) {
        // 捕获并输出错误,返回服务器错误响应
        console.error("查询资源出错:", err);
        res.status(500).send("服务器内部错误");
    }
});

2. 优化模型(可选但推荐)

为slug字段添加唯一索引,确保每个资源的slug不重复,同时提升查询效率:

var resourceSchema = new mongoose.Schema({
    // 其他字段保持不变
    slug: { 
        type: String, 
        required: true, 
        unique: true // 添加唯一约束
    },
    // 其他字段保持不变
});

关键注意事项

  • Slug唯一性:必须保证每个资源的slug唯一,否则findOne只会返回第一个匹配的资源,导致逻辑错误。
  • 错误处理:始终在async路由中添加try/catch块,捕获数据库查询或渲染过程中的异常。
  • 404处理:当未找到对应slug的资源时,返回明确的404响应,避免前端出现空白页面。

内容的提问来源于stack exchange,提问作者Andrew Buccellato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 13:30:52