【问题标题】:Express.js Cannot read property 'req' of undefinedExpress.js 无法读取未定义的属性“req”
【发布时间】:2017-01-23 08:13:32
【问题描述】:

我的 Express.js 应用程序一直在抛出 Cannot read property 'req' of undefined。本质上,它监听GET 请求,获取content 查询,然后用表格回复。以下是出现问题的部分。

index.js

var panels = require('./modules/panels.js');
app.get('/panel', function (req, res) {
    var user;
    if (user = req.session.user) {
        panels.getContents(req.query.content, user.innId, res.send);
    } else {
        res.sendStatus(401);
    }
});

modules/panels.js

exports.getContents = function(panelName, innId, callback) {
    var response = "";
    switch (panelName) {
        case 'tenants':
            con.query(queryString, queryParams, function(err, rows) {
                if (err) {
                    handle(err);
                } else {
                    if (rows.length == 0) {
                        var tenants = 0;
                        var debtors = 0;
                    } else {
                        var tenants = rows[0].tenants;
                        var debtors = rows[0].length;
                    }
                    response = convertToHTMLTable(rows);
                }
                callback(response); /*THE ERROR POINTS HERE */
            });
            break;

        /* other cases here */

        default:
            response += "Invalid Request";
            callback(response);
    }
}

我做错了什么?我的猜测是我不应该将res.send 作为回调传递。那么,我该如何解决呢?

【问题讨论】:

  • 您是否尝试将 res.send 替换为 () => res.send()
  • user = req.session.user 应该是user == req.session.user,究竟是哪一行引发了错误?
  • @AdamAzad 不,我想将会话分配给用户,同时检查它是否真实。我在错误的行上发表了评论。它在 panel.js 中。
  • @UlysseBN 是的,看起来这就是问题所在。
  • @starleaf1 好的,我已经遇到了类似的问题:查看here 了解更多信息。

标签: javascript node.js express


【解决方案1】:

我也遇到了这个错误,在仔细阅读错误消息并盯着我的代码太久之后,它点击了。

我(和上面的提问者)的代码如下所示:

  somethingAsync
  .then(res.send) // <-- storing send() divorced from parent object "res"
}

问题是,当 res.send 稍后被调用时,它脱离了它的动态范围——这意味着在 send 方法内部调用 this,现在通常引用 res请参阅global。显然,res.send 包含对this.req 的引用,给出了错误消息。

等价场景:

res = {
    send: function() { 
        console.log(this.originalMessage.req);
    },
    originalMessage: { req: "hello SO" },
};

res.send();
// # "hello SO"
const x = {};
x.send = res.send;
x.send();
// # Uncaught TypeError: Cannot read property 'req' of undefined

或者,换一种说法:

new Promise(_ => _())
.then(_ => console.log(this.msg.req));
// # Uncaught (in promise) TypeError: Cannot read property 'req' of undefined

两种解决方案:

handler(req, res) {
  somethingAsync
  .then(() => res.send())
   // ^ send will be called as a method of res, preserving dynamic scope
   // that is, we're storing a function that, when called, calls
   // "res.send()", instead of storing the "send" method of "res" by itself.
}

理论上更惯用的方法是

handler(req, res) {
  somethingAsync
  .then(res.send.bind(res))
  //^ res is explicitly bound to the saved function as its dynamic scope
}

动态作用域的有害小问题,那个。似乎 express 应该放弃那里的动态范围,或者至少抛出一个更好的错误......

【讨论】:

  • 刚刚也遇到了这个问题。谢谢!
【解决方案2】:

index.js

中试试这个
panels.getContents(req.query.content, user.innId, res);

并进入 panel.js

exports.getContents = function(panelName, innId, response) {
    var response = "";
    switch (panelName) {
        case 'tenants':
            con.query(queryString, queryParams, function(err, rows) {
                if (err) {
                    handle(err);
                } else {
                    if (rows.length == 0) {
                        var tenants = 0;
                        var debtors = 0;
                    } else {
                        var tenants = rows[0].tenants;
                        var debtors = rows[0].length;
                    }
                    response.send(convertToHTMLTable(rows));
                }
            });
            break;

        /* other cases here */

        default:
            error += "Invalid Request";
            response.send(error)
    }
}

【讨论】:

  • 未来读者请注意:在此答案生效之前我必须进行一些修改,但我无法在不透露太多代码的情况下进行编辑。
【解决方案3】:

当您将 res.send 作为参数传递给 getContents 函数 (panels.getContents(req.query.content, user.innId, res.send);) 时,它会传入一个新变量,您将其命名为 callback

所以res.send 现在被从原来的/假定的lexical context/binding 中删除 在这种情况下是res 对象,并且似乎res.send 使用res 对象中的req 属性使用this.req

您在这里所做的是无意中将 this 的值更改为函数 send 成为全局对象。

解决方案

有两种方法可以解决这个问题

  • panels.getContents(req.query.content, user.innId, () =&gt; res.send);

// 或

  • panels.getContents(req.query.content, user.innId, res.send.bind(res));

在第二个解决方案中,您绑定函数 res.send 以始终将 this 的任何值视为 res 对象 (bind it to the res object)

【讨论】:

    猜你喜欢
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2020-04-06
    • 2020-10-30
    • 2019-10-09
    • 1970-01-01
    相关资源
    最近更新 更多