Nodejs的动态视图

Nodejs的动态视图

学习《Node.js开发指南》遇到一个问题:动态视图的实现问题 首先书中第五章sample中‘视图交互’一节: app.dynamicHelpers({ user:function(req,res){ return res.session.user; }, error:function(req,res){ var err = req.flash(‘error’); if(err.length) return err; else return null; }, success:function(req,res){ var succ = req.flash(‘success’); if(succ.length) return succ; else return null; } }); 此版本在Express 3.0之后就不支持了,网上介绍使用 res.locals代替: app.use(function(req,res,next){ var err = req.flash(‘error’); var success = req.flash(‘success’); res.locals.user = req.session ? req.session.user : null; res.locals.error = err.length ? err : null; res.locals.success = success.length ? success : null; next(); }); app.use(app.router); routes(app); 问题是我如此做一直没有效果,即视图的效果没有,我的请求不会调用这段逻辑,我在此方法里面断点debugger了,可是一直执行不到,直接导致res.locals.user,error,success的值一直都是undefinded。

我想请教大家,这个动态视图是如何实现的,我的问题出在哪里? var express = require(‘express’); var routes = require(’./routes’); var user = require(’./routes/user’); var http = require(‘http’); var path = require(‘path’); var util = require(‘util’); var flash = require(‘connect-flash’);

var app = express(); var engine = require(‘ejs-locals’); var MongoStore = require(‘connect-mongo’)(express); var settings = require(’./settings’); var sessionStore = new MongoStore({ db : settings.db }, function() { console.log(‘connect mongodb success…’); });

app.configure(function () { // all environments app.set(‘port’, process.env.PORT || 3000); //since express 3.0 use ejs-locals app.engine(‘ejs’, engine);

app.set(‘views’, __dirname + ‘/views’); app.set(‘view engine’, ‘ejs’); app.use(express.favicon()); app.use(express.logger(‘dev’)); app.use(express.bodyParser()); app.use(flash()); app.use(express.methodOverride());

app.use(express.cookieParser()); app.use(express.session({ secret:settings.cookieSecret, cookie : { maxAge : 60000 * 20 //20 minutes }, store:sessionStore }));

app.use(function(req,res,next){ var err = req.flash(‘error’); var success = req.flash(‘success’); res.locals.user = req.session ? req.session.user : null; res.locals.error = err.length ? err : null; res.locals.success = success.length ? success : null; next(); }); app.use(app.router); app.use(express.static(path.join(__dirname, ‘public’))); });

// development only if (‘development’ == app.get(‘env’)) { app.use(express.errorHandler()); } routes(app);

http.createServer(app).listen(app.get(‘port’), function(){ console.log('Express server listening on port ’ + app.get(‘port’)); }); 插件我也都装了: { “name”: “aine blog”, “version”: “0.0.1”, “private”: true, “scripts”: { “start”: “node app.js” }, “dependencies”: { “express”: “3.3.8”, “ejs”: “", “connect”: “1.8.5”, “connect-mongo”:">= 0.1.7", “mongodb”:">= 0.0.9", “connect-flash”:"” } } 是不是什么插件版本不兼容呢?请高手指教。。。。


4 回复

在Node.js应用中,动态视图的实现主要依赖于res.locals对象来存储一些在视图渲染过程中需要使用的数据。根据你描述的情况,问题可能出在中间件的顺序或者某些配置上。以下是一个简化且更清晰的实现方式,帮助你解决这个问题。

问题分析

  1. 中间件顺序:确保app.use(...)的顺序正确。
  2. 插件版本:确保所有依赖插件的版本兼容。
  3. 会话管理:确保会话(session)已正确设置并启用。

解决方案

首先,确保你的app.js文件中包含正确的依赖项和配置。以下是调整后的代码示例:

var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var util = require('util');
var flash = require('connect-flash');

var app = express();

// 设置引擎
var engine = require('ejs-locals');
app.engine('ejs', engine);

// 配置视图引擎
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// 中间件配置
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());

// Cookie解析器
app.use(express.cookieParser());

// 会话配置
app.use(express.session({
    secret: 'your_secret_key',
    cookie: { maxAge: 60000 * 20 }, // 20分钟
    store: new MongoStore({ db: 'your_database_name' })
}));

// 使用flash插件
app.use(flash());

// 动态视图助手
app.use(function(req, res, next) {
    var err = req.flash('error');
    var success = req.flash('success');
    res.locals.user = req.session ? req.session.user : null;
    res.locals.error = err.length ? err : null;
    res.locals.success = success.length ? success : null;
    next();
});

// 路由
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// 错误处理
if ('development' === app.get('env')) {
    app.use(express.errorHandler());
}

// 启动服务器
http.createServer(app).listen(app.get('port'), function() {
    console.log('Express server listening on port ' + app.get('port'));
});

关键点解释

  1. 中间件顺序:确保app.use(express.session())app.use(flash())app.use(function(req, res, next) {...})之前。
  2. 会话配置:确保会话配置正确,包括secretstore
  3. Flash消息:确保req.flash()方法被正确使用,并且在模板中显示这些消息。

模板示例

在EJS模板中,你可以这样访问这些变量:

<% if (error) { %>
    <div class="alert alert-error"><%= error %></div>
<% } %>

<% if (success) { %>
    <div class="alert alert-success"><%= success %></div>
<% } %>

<% if (user) { %>
    <p>Welcome, <%= user.name %></p>
<% } else { %>
    <p>Please login</p>
<% } %>

通过以上调整,你应该能够解决动态视图的问题。如果仍然有问题,请检查日志和错误信息,确保每个步骤都按预期工作。


github 搜 cnode

它的配置文件拿下来

断点使用inspector

我自己debugger了过程,发现这段代码始终执行不到,准确的说是断点断不到(具体在什么时候执行无法考究): app.use(function(req,res,next){ var err = req.flash(‘error’); var success = req.flash(‘success’); res.locals.user = req.session ? req.session.user : null; res.locals.error = err.length ? err : null; res.locals.success = success.length ? success : null; next(); }); 我跟踪了传给engine的参数里是有flash()进去的值,原来是我的页面引用错了,我依然通过locals.user或者locals.error来引用了,其实不需要,直接使用error或者success即可取到相应的值。

思考:对于动态视图的实现逻辑: res.render = function(view, options, fn){ … options._locals = self.locals; … } 我猜想在我们flash的时候,就是把对应的值写到了self.locals容器里,然后在render方法中赋值给view的option,而在option中保存的格式已经和index定义的一样了,翻译成: [settings=[Object],user=undefined,error=[Array],success=null,title=“用户注册”, +1…] 这样就可以在页面上直接引用了! index中定义的是: app.get(’/reg’,function(req,res){ res.render(‘reg’,{ title: ‘用户注册’ }); }); 通过上面的代码,动态的加了user,error,success几个变量的定义。

综上是我的分析,终结此帖,谢谢大家!

从你的描述来看,问题可能出在几个方面。以下是一些可能的原因及解决方案:

1. req.flash 的使用

确保你已经在路由或中间件中正确使用了 req.flash 来设置错误或成功消息。例如:

app.post('/login', function(req, res) {
    // 登录处理逻辑
    if (!user) {
        req.flash('error', '用户名或密码错误');
    } else {
        req.flash('success', '登录成功');
    }
    res.redirect('/');
});

2. express-session 中间件的顺序

确保 express-session 中间件在 flash 之前被调用,否则 req.session 可能为 undefined

app.use(express.cookieParser());
app.use(express.session({ secret: settings.cookieSecret }));
app.use(flash());

3. res.locals 设置的时机

确保 res.locals 设置在所有路由中间件之后,但在实际路由处理之前。你可以将 res.locals 设置放在 app.use 中:

app.use(function(req, res, next) {
    var err = req.flash('error');
    var success = req.flash('success');
    res.locals.user = req.session ? req.session.user : null;
    res.locals.error = err.length ? err : null;
    res.locals.success = success.length ? success : null;
    next();
});

app.use(app.router);

4. 确保 Express 版本正确

确保你使用的 Express 版本与文档一致。如果你使用的是 Express 3.x,可以按照上面的代码进行配置。如果你使用的是 Express 4.x,app.router 已经被移除,你可以直接使用路由中间件:

app.use('/', routes);
app.use('/users', user);

5. 插件版本检查

确保所有插件版本兼容。你可以在 package.json 中指定正确的版本号,并运行 npm install 来安装这些版本:

"dependencies": {
    "express": "3.3.8",
    "ejs": "*",
    "connect": "1.8.5",
    "connect-mongo": ">= 0.1.7",
    "mongodb": ">= 0.0.9",
    "connect-flash": "*"
}

通过以上步骤,你应该能够解决 res.locals 没有正确设置的问题。如果问题仍然存在,请检查是否有其他中间件干扰了请求处理流程。

回到顶部