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

Express中间件SQL取数传递至EJS公共模板渲染为空如何解决

问题背景

正在搭建内容管理系统,期望支持系统管理员修改所有HTML页面元数据等全局系统属性,当前遇到问题:传递给EJS模板的对象数据无法正常渲染,最终输出结果为空。

问题截图

现有代码与运行状态

Settings Controller(模块运行正常)

// Get all data from the settings to display it on evre page.
exports.data = (req, res, next) => {
    db.query('SELECT * FROM settings', async (error, results, fields) => {
        if (error) {
            console.log(error)
            return next()
        } else {
            const settings = results[0]
            console.log(settings)
            next()
        };
    })
}

settings.js 路由(模块运行正常)

const express = require("express");
const settingsController = require("../controller/settings")
const router = express.Router();

// get all data from database
router.get('/settings', settingsController.data );

module.exports = router;

模板结构说明

EJS页面通过include语法引入公共组件,需要修改的是公共HTML头部内容。

index 首页模板(运行正常)

<%- include('./partials/head'); %>
</head>
<body>
<%- include('./partials/navbar'); %>
<%- include('./partials/footer'); %>

page.js 路由(运行正常)

// use res.render to load up an ejs view file
// index page
// 已挂载settings Middleware
router.get('/', authController.isLoggedIn,settingsController.data,indexController.home);

异常位置

head.ejs 公共头部模板(模板变量渲染为空)

<!DOCTYPE html>
<html lang="en">
    <head>
    <!-- 此处渲染为空 -->
    <meta name="description" content="<%= settings.description %>">

客户端侧渲染后的首页源码(meta标签content属性为空)

<!DOCTYPE html>
<html lang="en">
    <head>
    <!-- 内容为空 -->
    <meta name="description" content="">
问题原因与解决方案

核心原因

settingsController.data中间件查询到settings数据后,仅将数据存在了中间件函数的局部作用域中,既没有挂载到请求/响应对象传递给后续中间件,也没有在调用res.render时传入模板,EJS无法读取到settings变量,最终渲染结果为空。

修复步骤

  • 修改settings中间件,把查询到的配置挂载到res.locals上。Express的res.locals对象专门用于存储需要传递给模板的变量,挂载后所有后续渲染流程、include引入的子模板都可以直接访问对应变量,不需要逐层手动传参。
    修改后的Settings Controller代码:
    // Get all data from the settings to display it on every page.
    exports.data = (req, res, next) => {
        db.query('SELECT * FROM settings', async (error, results, fields) => {
            if (error) {
                console.log(error)
                // 查询异常时设置默认值,避免模板渲染报错
                res.locals.settings = { description: '' }
                return next()
            } else {
                // 将查询到的配置挂载到res.locals,模板可直接访问
                res.locals.settings = results[0]
                next()
            };
        })
    }
    
  • 确认indexController.home中调用res.render时,不要覆盖res.locals内的settings字段即可。res.render传入的参数对象会和res.locals自动合并,挂载到res.locals的全局变量会自动注入所有模板,包括include引入的head、navbar、footer这类公共组件,不需要额外处理。

额外优化建议

  • 全局配置属于所有页面都需要的公共数据,不需要在每个路由里单独挂载settingsController.data中间件,直接在业务路由挂载前注册全局中间件即可,一次配置所有路由自动生效:
    // 注册全局中间件,所有路由渲染前自动拉取系统配置
    app.use(settingsController.data)
    
  • 建议给系统配置增加本地缓存,避免每次页面请求都查询数据库,降低数据库压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:54:28