【问题标题】:NodeJS Unhandled rejection error: Can't set headers after they are sentNodeJS未处理的拒绝错误:发送后无法设置标头
【发布时间】:2016-09-02 19:38:18
【问题描述】:

我最近参与了一个 nodejs 项目,在尝试在我的数据库访问和路由之间使用 promise 时,我遇到了错误Can't set headers after they are sent回复http://localhost:8080/api/user。虽然我知道堆栈中的许多解决方案都没有为我解决,所以这是我在 router.js

的路由代码
 server.get('/api/user/', function (req, res) {

        database.getUser()
            .then(function(data){
                res.send(data);
            }, function(err){

                res.send(500,{error: err});
            });

    });

database.js 的第一部分包括函数 getUser

(function() {

'use strict';
var Promise = require('bluebird'), 
    mysql = require("mysql"),
    bcrypt = require('bcryptjs'),
    client;

exports.connect = function(){
    return new Promise(function(resolve, reject) {
        client = mysql.createPool({
                connectionLimit : 100,
                waitForConnection: true,
                host     : 'localhost',
                user     : 'root',
                password : 'root',
                database : 'public',
                debug    :  false
            });
            if(!client){
                reject('Deu merda');
            }
            else{
                resolve();
            }
    });
}


exports.getUser = function(){
     return new Promise(function (resolve, reject) { 
     var query = "SELECT name FROM public.users";
     query = mysql.format(query);
     client.query(query,function (err, result) {
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            });   
     });
}

任何帮助都会很棒,在此先感谢您!

编辑:我再次检查我的代码,并且我有一个中间件来检查用户是否有权访问某个页面,因为它是我可以在这里更改某些内容的最后一个选项之一:

 (function() {

    'use strict';

    var routes = require("./routes"),
        cookie = require("./utils");

    module.exports = function(req, res, next) {

        var i;

        if (req.url.split('/')[1] == 'api') {

            // START REGION: API permissions (all)
            for (i = 0; i < routes.api.all.length; i++) {
                if (routes.api.all[i].indexOf(req.url) > -1) {
                    break;
                }
            }
            if (i != routes.api.all.length) {
                next();
            } else {

                // END REGION: API permissions (all)

                // START REGION: API permissions (logged)
               cookie.verifySession(req.cookies.session)
                    .then(function (userId) {

                        for (i = 0; i < routes.api.logged.length; i++) {
                            if (req.url.indexOf(routes.api.logged[i]) > -1) {
                                break;
                            }
                        }

                        if (i == routes.api.logged.length) {
                            return res.sendStatus(403);
                        } else {
                            next();
                        }

                    })
                    .catch(function (err) {
                        return res.sendStatus(403);
                    });

            }

            // END REGION: API permissions (logged)

        } else {

            // START REGION: Views permissions (all)

            cookie.verifySession(req.cookies.session)
                .catch(function (err) {
                    if (res.statusCode == null) {
                        return res.redirect('/forbidden');
                    }
                });

            for (i = 0; i < routes.views.all.length; i++) {
                if (routes.views.all[i].indexOf(req.url) > -1) {
                    break;
                }
            }

            if (i != routes.views.all.length) {
                next();
            } else {

                // END REGION: Views permissions (all)

                // START REGION: Views permissions (logged)

                cookie.verifySession(req.cookies.session)
                    .then(function (userId) {

                        for (i = 0; i < routes.views.logged.length; i++) {
                            if (req.url.indexOf(routes.views.logged[i]) > -1) {
                                break;
                            }
                        }

                        if (i == routes.views.logged.length) {
                            if (res.statusCode == null) {
                                return res.redirect('/forbidden');
                            }
                        } else {
                            next();
                        }

                    });

            }

            // END REGION: Views permissions (logged)

        }
        next();
}
}());

我有一个添加许可的辅助文件:

  {
    "api":{
        "all": [
            "/api/authenticate",
            "/api/user"
        ],

        "logged": [
            "/api/lessons"
        ],

        "admin": [

        ]
    },

    "views":{
        "all": [
            "/",
            "/user_management"
        ],
        "logged": [],
        "admin": [],
        "advanced": []


    }
}

【问题讨论】:

  • 在将内容发送到浏览器后,您尝试修改标题的地方。不幸的是,它似乎不在发布的代码中。
  • 我应该在哪里寻找错误的任何想法?老实说,我已经尝试了一点点,但我似乎无法找到我陷入的陷阱。
  • 在我看来,您的中间件可以多次调用next()。您可能希望在调用 next() 后返回,因此这些路径都不会到达函数末尾的最后一个 next()
  • 我认为在这种特殊情况下不会发生这种情况,因为我认为,我们只会经历第一个 for + if 并离开,你不这么认为吗?
  • 您在中间件函数的末尾调用next()。因此,在此之前没有返回的任何代码路径都将返回 next()。但其他一些代码路径也有自己对next() 的调用。这是一个双重电话。基本上,您的中间件没有正确考虑其异步操作,并且没有唯一的逻辑路径,这些路径只会导致每个请求仅调用一次 next()res.redirect()

标签: javascript mysql node.js express angular-promise


【解决方案1】:

因为这回答了你的问题,所以我会在答案中发表评论:

在我看来,您的中间件可以多次调用next()

您在中间件函数的末尾调用next()。因此,在此之前没有返回的任何代码路径都将返回 next()。但其他一些代码路径也有自己的对next() 的调用。这是一个双重电话。基本上,您的中间件没有正确考虑其异步操作,并且没有唯一的逻辑路径,只会导致每个请求仅调用一次 next()res.redirect()

【讨论】:

  • 我有一个类似的问题:我在 then() 中检查 express-Validator 的验证结果,如果有错误则重定向,但我的成功重定向在 then() 之外,而不是承诺。因此两者都被执行了,我得到了“发送后无法设置标题”错误。你的回答让我很开心。
猜你喜欢
  • 1970-01-01
  • 2023-04-04
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-20
相关资源
最近更新 更多