关于node.js:ExpressJS res.render()错误(JSON.stringify无法在循环引用上工作)

ExpressJS res.render() error (JSON.stringify can't work on circular reference)

这有什么不对?

res.render('/somepage', {user:req.session.user})

它导致

1
Converting circular structure to JSON

错误,(导致会话元素具有循环用户引用。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<wyn>
exports.home =  function (req, res) {
    var entityFactory = new require('../lib/entity-factory.js').EntityFactory();
    entityFactory.get_job_task_lists({
        callback : function (err, job_task_lists) {
            res.render('home.jade', {
                        locals:{
                            title: 'Logged in.',
                            user:req.session.user, // does not work
                            job_task_lists:job_task_lists || []
                        }
            });
        }
    });
};

</wyn>

我在node_modules/express/node_modules/connect/lib/middleware/session/memory.js中添加了一些日志记录

1
2
3
4
5
6
7
8
MemoryStore.prototype.set = function(sid, sess, fn){
  var self = this;
  process.nextTick(function(){

    console.log(sess); //this is giving the output listed

    self.sessions[sid] = JSON.stringify(sess);
...

就结构而言,这就是我期望会话的样子:

1
2
3
4
5
6
7
8
9
10
11
{ lastAccess: 1330979534026,
  cookie:
   { path: '/',
     httpOnly: true,
     _expires: Tue, 06 Mar 2012 00:32:14 GMT,
     originalMaxAge: 14399999 },
  user: // this is the object I added to the session
   { id: 1,
     username: 'admin',
     password: '8e3f8d3a98481a9073d2ab69f93ce73b',
     creation_date: Mon, 05 Mar 2012 18:08:55 GMT } }

但这是我发现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
{ lastAccess: 1330979534079, // new session
  cookie:
   { path: '/',
     httpOnly: true,
     _expires: Tue, 06 Mar 2012 00:32:14 GMT,
     originalMaxAge: 14399999 },
  user:  // but here it is again, except now it's a mashup,
         // containing members it shouldn't have, like locals,
         // and, well, everything but the first 4 properties
   { id: 1,
     username: 'admin',
     password: '8e3f8d3a98481a9073d2ab69f93ce73b',
     creation_date: '2012-03-05T18:08:55.701Z',
     locals:
      { title: 'Logged in.',
        user: [Circular], //and now it's circular
        job_task_lists: [Object] },
     title: 'Logged in.',
     user: [Circular],
     job_task_lists: [ [Object], [Object], [Object], getById: [Function] ],
     attempts: [ '/home/dan/development/aqp/views/home.jade' ],
     scope: {},
     parentView: undefined,
     root: '/home/dan/development/aqp/views',
     defaultEngine: 'jade',
     settings:
      { env: 'development',
        hints: true,
        views: '/home/dan/development/aqp/views',
        'view engine': 'jade' },
     app:
      { stack: [Object],
        connections: 6,
        allowHalfOpen: true,
        _handle: [Object],
        _events: [Object],
        httpAllowHalfOpen: false,
        cache: [Object],
        settings: [Object],
        redirects: {},
        isCallbacks: {},
        _locals: [Object],
        dynamicViewHelpers: {},
        errorHandlers: [],
        route: '/',
        routes: [Object],
        router: [Getter],
        __usedRouter: true },
     partial: [Function],
     hint: true,
     filename: '/home/dan/development/aqp/views/home.jade',
     layout: false,
     isPartial: true } }

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Converting circular structure to JSON
    at Object.stringify (native)
    at Array.0 (/home/dan/development/aqp/node_modules/express/node_modules/connect/lib/middleware/session/memory.js:77:31)
    at EventEmitter._tickCallback (node.js:192:40)

查看用户对象是如何嵌套的?

  • 请注意,这次我没有明确地使用'locals'发送值,但最终只有一个(这就是循环引用的来源)。

看起来会话正用于将对象传输到视图。

这是我唯一的中间件(它只从会话中读取):

1
2
3
4
5
6
7
function requiresAuthentication(req, res, next){
    if (req.session.user){
        next();
    } else {
        next(new Error('Unauthorized. Please log in with a valid account.'))
    }
}

并且我唯一一次修改req.session就在这条路线上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.post('/home', function (req,res,next) {
    var auth = require('./lib/authentication');
    auth.authenticate_user(req.body.user, function (user) {
        if (user){
            req.session.user = user;
            console.log('authenticated');
            res.redirect(req.body.redir || '/home');
            //next();
        } else {
            console.log('not authenticated');
            res.render('logins/new.jade', {title: 'Login Failed', redir:''})
        }
    });
});

我的申请中还没有其他的东西,因为它还很年轻。我知道我自己并没有在任何地方破坏会议;我检查了。

我做了一些测试,当我尝试在页面上使用局部变量时,这似乎只是一个问题。例如,这是我的观点home.jade

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
div(data-role="page")
    div(data-role="header")
        a(href='/logout', data-icon='delete', data-ajax="false") Log out
        h1= title
        a(href='/account', data-icon='info', data-ajax="false") Account

        != partial('user', user)


    each jtl in job_task_lists
        div(id=jtl.name, class = 'draggable_item', style='border:2px solid black;')
            #{jtl.name} - #{jtl.description}
        a(data-icon='plus')


    div(data-role="footer")
        h3 footer

script(src="/javascripts/home.js")

如果我将用户注释掉部分,则会呈现,否则我会遇到此Converting circular structure to JSON问题。

UPDATE
所以在连接eclipse和v8调试器之后,我一直在逐步完成代码,我知道会话和用户对象的混搭在哪里,

node_modules/connect/lib/middleware/session/session.js

utils.union最终将用户对象的成员混合到会话中,从而导致循环引用。我只是不确定为什么(诚然可能是我的代码)


这是在视图中修改会话数据的问题。

经过多次挖掘,我发现这是2.5.8中部分处理方式的错误。 我提交了一个问题,然后是一个补丁。 (如果有人在将来需要此信息),因为npm仍在提供Express 2.5.8 AFAIK。

感谢您的帮助@freakish和@Ryan