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

如何在Koa/Express所有路由中共享全局侧边栏/页脚并复用博客查询?

解决Koa/Express中全局侧边栏重复查询的问题

当然可以搞定!你现在每个路由都重复查侧边栏博客的问题,本质是没利用好框架的中间件机制或者缓存策略,我给你分享几个实用的方案,分框架给你举例子:

方案一:全局中间件(最推荐)

不管是Express还是Koa,中间件都是处理这类“所有请求都需要的公共数据”的最佳方式——它能在所有路由处理之前统一执行查询,然后把结果挂载到请求/上下文对象上,后续所有路由直接用就行,完全不用重复写查询代码。

Express 实现示例

// 先定义一个获取最新博客的全局中间件
app.use(async (req, res, next) => {
  try {
    // 这里替换成你的实际查询逻辑,比如从MongoDB取最新5篇
    req.latestBlogs = await BlogModel.find().sort({ createdAt: -1 }).limit(5);
    next(); // 放行,继续执行后面的路由
  } catch (err) {
    // 万一查询出错,做个降级处理,别让页面崩了
    console.error('侧边栏博客查询失败:', err);
    req.latestBlogs = [];
    next();
  }
});

// 现在你的路由可以直接用req.latestBlogs了
app.get('/home', (req, res) => {
  res.render('home', { latestBlogs: req.latestBlogs });
});

app.get('/about', (req, res) => {
  res.render('about', { latestBlogs: req.latestBlogs });
});

Koa 实现示例

Koa里推荐把公共数据挂到ctx.state上(这是Koa官方建议的上下文数据传递方式):

// 全局中间件
app.use(async (ctx, next) => {
  try {
    ctx.state.latestBlogs = await BlogModel.find().sort({ createdAt: -1 }).limit(5);
    await next(); // 执行后续的路由/中间件
  } catch (err) {
    console.error('侧边栏博客查询失败:', err);
    ctx.state.latestBlogs = [];
    await next();
  }
});

// 路由里直接用ctx.state.latestBlogs
router.get('/home', async (ctx) => {
  await ctx.render('home', { latestBlogs: ctx.state.latestBlogs });
});

router.get('/about', async (ctx) => {
  await ctx.render('about', { latestBlogs: ctx.state.latestBlogs });
});

方案二:加缓存优化(减少数据库压力)

如果你的博客不是每秒都更新,完全没必要每次请求都查数据库——可以把查询结果缓存一段时间,比如5分钟,这样能大幅降低数据库的查询次数,提升性能。

结合中间件的缓存示例(Express为例)

// 定义缓存变量和过期时间
let cachedLatestBlogs = null;
let cacheExpire = 0;
const CACHE_TIME = 5 * 60 * 1000; // 5分钟有效期

app.use(async (req, res, next) => {
  const now = Date.now();
  // 缓存不存在或者过期了,重新查询
  if (!cachedLatestBlogs || now > cacheExpire) {
    try {
      cachedLatestBlogs = await BlogModel.find().sort({ createdAt: -1 }).limit(5);
      cacheExpire = now + CACHE_TIME;
    } catch (err) {
      console.error('侧边栏博客查询失败:', err);
      cachedLatestBlogs = [];
    }
  }
  req.latestBlogs = cachedLatestBlogs;
  next();
});

⚠️ 这里要提醒你:别直接用全局变量存请求级的实时数据!你说的“全局变量”如果是模块级的变量(比如let latestBlogs = []),如果不加缓存过期逻辑,数据会一直是第一次查询的结果,除非重启服务——而用中间件挂到请求对象上,每个请求都能拿到最新的(或缓存的)数据,才是正确的做法。

方案三:模板引擎全局变量(适合低更新频率场景)

如果你用的是EJS、Pug这类模板引擎,还可以把侧边栏数据设为模板的全局变量,这样所有模板都能直接用,连路由里传参的步骤都省了。

Express + EJS 示例

// 先给模板引擎设置全局变量,初始为空数组
app.locals.latestBlogs = [];

// 定时更新这个全局变量,比如每5分钟更一次
setInterval(async () => {
  try {
    app.locals.latestBlogs = await BlogModel.find().sort({ createdAt: -1 }).limit(5);
  } catch (err) {
    console.error('更新侧边栏缓存失败:', err);
  }
}, 5 * 60 * 1000);

// 路由里渲染模板时,不用再传latestBlogs了
app.get('/home', (req, res) => {
  res.render('home'); // 模板里直接用<% latestBlogs.forEach(blog => { ... }) %>
});

这种方式适合博客更新不频繁的场景,因为是定时更新,不是每次请求都查数据库。

总结一下,最实用的就是中间件+可选缓存的组合,既保证每个请求能拿到需要的数据,又能灵活优化性能,还彻底解决了重复代码的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:16:33