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

从ExpressJS的app.locals渲染EJS模板时为何出现“未定义”错误?

ExpressJS中app.locals变量未定义问题的解决

问题描述

在ExpressJS应用中编写了如下请求端点代码:

app.get('/', (req, res, next) => {

    db.collection('sys_params').find().toArray((err, sysParams) => {
        if (err) throw err;

        app.locals.landPageRolloverStatus = sysParams[0].landPageRolloverStatus;
        app.locals.ludenourOnlineStatus = sysParams[0].ludenourOnlineStatus;
        app.locals.ludenourContactUsEnabled = sysParams[0].ludenourContactUsEnabled;
        app.locals.ludenourJobsEnabled = sysParams[0].ludenourJobsEnabled;  

        console.log(sysParams)
        app.locals.sysParams = sysParams; 

    });

    res.render('index2');
    next()

});

渲染EJS模板index2.ejs时,出现如下错误:

ReferenceError: /Users/falswaimil/Documents/Project3X/Master/AIRECP/AirECPRetails/online-store/views/index2.ejs:39
     37|           
     38|         <a class="navbar-brand float-xs-right float-sm-left" href="http://localhost:3002/?clang=en"><img src="img/lu3.svg" class="img-fluid"/></a>
 >>  39|         <% if (sysParams[0].ludenourOnlineStatus == "UC" ) { %>
     40| 
     41|             <% if (clang == "en") {  %>
     42|                 <p style="color:red; font-family:Arial Rounded MT Bold; font-size:130%; text-align:center; width: 100%;"><%= __('SiteUnderConstruction') %></p>   
sysParams is not defined

但刷新页面后模板能正常渲染,用户疑惑:app.locals作为应用级变量,应该跨请求在EJS模板中可用,为什么会出现这个问题?

问题原因

核心问题是异步代码执行顺序:

  • 数据库查询db.collection('sys_params').find().toArray()是异步操作,它的回调函数会在查询完成后才执行。
  • 当前代码中,res.render('index2')和next()是在数据库查询发起后立即执行的,此时回调还没跑完,app.locals.sysParams还没被赋值,所以模板渲染时找不到该变量。
  • 刷新页面时,上一次请求的异步回调已经完成,app.locals.sysParams已经被赋值,所以模板能正常读取。

解决方法

需要确保在数据库查询完成、app.locals赋值完成后,再执行模板渲染。有两种常用方式:

方式1:将res.render放入异步回调内

app.get('/', (req, res, next) => {
    db.collection('sys_params').find().toArray((err, sysParams) => {
        if (err) {
            // 错误处理,避免直接throw导致应用崩溃
            return next(err);
        }

        app.locals.landPageRolloverStatus = sysParams[0].landPageRolloverStatus;
        app.locals.ludenourOnlineStatus = sysParams[0].ludenourOnlineStatus;
        app.locals.ludenourContactUsEnabled = sysParams[0].ludenourContactUsEnabled;
        app.locals.ludenourJobsEnabled = sysParams[0].ludenourJobsEnabled;  
        app.locals.sysParams = sysParams; 

        // 赋值完成后再渲染模板
        res.render('index2');
        next();
    });
});

方式2:使用async/await简化异步代码

app.get('/', async (req, res, next) => {
    try {
        const sysParams = await db.collection('sys_params').find().toArray();
        
        app.locals.landPageRolloverStatus = sysParams[0].landPageRolloverStatus;
        app.locals.ludenourOnlineStatus = sysParams[0].ludenourOnlineStatus;
        app.locals.ludenourContactUsEnabled = sysParams[0].ludenourContactUsEnabled;
        app.locals.ludenourJobsEnabled = sysParams[0].ludenourJobsEnabled;  
        app.locals.sysParams = sysParams; 

        res.render('index2');
        next();
    } catch (err) {
        next(err);
    }
});

额外说明

  • app.locals确实是应用级变量,一旦赋值后会在后续所有请求中生效,但第一次请求时必须确保赋值完成后再渲染模板。
  • 建议不要直接在回调中throw err,应该通过next(err)把错误交给Express的错误处理中间件,避免应用崩溃。

内容的提问来源于stack exchange,提问作者فوزي الصويمل Fawzi Alswaimil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:30:16