节点,Express,Passport,Credential - 错误:发送后无法设置标头

时间:2016-06-09 15:55:59

标签: javascript node.js express passport.js

我在尝试在我的应用程序中构建访问控制机制时遇到了一个问题。我在这个网站上看了很多答案,但我似乎无法找到解决我问题的答案。所以我刚刚注册并决定问自己。

我正在使用Passport而我正在实施本地策略。同时使用Credential作为我的密码哈希。这是我尝试以用户身份登录并在成功登录主页后重定向到用户时出现的错误:

_http_outgoing.js:346
    throw new Error('Can\'t set headers after they are sent.');
    ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (C:\src\bootstrap\node_modules\express\lib\response.js:718:10)
    at ServerResponse.send (C:\src\bootstrap\node_modules\express\lib\response.js:163:12)
at done (C:\src\bootstrap\node_modules\express\lib\response.js:957:10)
at Immediate._onImmediate (C:\src\bootstrap\node_modules\express-handlebars\lib\utils.js:26:13)
at tryOnImmediate (timers.js:543:15)
at processImmediate [as _immediateCallback] (timers.js:523:5)

涉及的文件:

的package.json

{
  "name": "bootstrap",
  "version": "1.0.0",
  "description": "Website of Bootstrap T-Shirts",
  "main": "bootstrap.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "bootstrap",
    "t-shirt",
    "tee shirt",
    "cloth",
    "shirt",
    "fashion"
  ],
  "author": "Kingson Chinedu Odogwu",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.15.0",
    "connect": "^3.4.1",
    "cookie-parser": "^1.4.1",
    "cors": "^2.7.1",
    "credential": "^1.0.0",
    "csurf": "^1.8.3",
    "express": "^4.13.4",
    "express-handlebars": "^3.0.0",
    "express-session": "^1.13.0",
    "method-override": "^2.3.5",
    "mongodb": "^2.1.14",
    "multer": "^1.1.0",
    "nodemailer": "^2.3.0",
    "passport": "^0.3.2",
    "passport-local": "^1.0.0"
  }
}

bootstrap.js

// load modules
const http = require('http');
const express = require('express');

var app = express();
var server;
var startServer;

require('./config.js')(app, server);
require('./routes.js')(app);

// custom 404 page
// this should appear AFTER all of your routes
app.use(function (req, res, next) {
    res.status(404).render('404');
});

// custom 500 page
// this should appear AFTER all of your routes
// note that even if you don't need the "next"
// function, it must be included for Express
// to recognize this as an error handler
app.use(function (err, req, res, next) {
    console.error(err.stack);
    res.status(500).render('500');
});

// END: APP SETTINGS

startServer = function startServer() {
    server = http.createServer(app).listen(app.get('port'), function () {
        console.log('Express started in ' + app.get('env') + 
        ' mode on http://localhost:' + app.get('port') + 
        '; press Ctrl-C to terminate...');
    });
};

if (require.main === module) {
    // application run directly; start app server
    startServer();
} else {
    // application imported as a module via "require": export function to create server
    module.exports = startServer;
}

config.js

// load modules
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const handlebars = require('express-handlebars').create({ defaultLayout: 'main' });
const multer = require('multer');
const credential = require('credential')();
const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
const session = require('express-session');
const appCredentials = require('./app-credentials.js');
const dbProvider = require('./lib/db-provider.js');

dbProvider.connect(appCredentials.dbUrl);

const storage = multer.diskStorage({
    destination: function destination(req, file, callback) {
        callback(null, __dirname + '/public/img');
    },
    filename: function filename(req, file, callback) {
        var i = file.mimetype.toString().indexOf('/');
        var l = file.mimetype.toString().length;
        var filetype = '.' + file.mimetype.toString().substring(i + 1, l);

        callback(null, Date.now() + filetype);
    }
});

const verify = (username, password, verified) => {
    dbProvider.findSet('user_accounts', "username", username, (result) => {
        var user = result[0];

        if (!user) {
            // No unexpected error, no user, reason for failure
            return verified(null, false, {
                message: 'User not found.'
            });
        }

        credential.verify(user.hash, password, (err, isValid) => {
            if (!isValid) {
                // No unexpected error, no user, reason for failure
                return verified(null, false, {
                    message: 'Incorrect password.'
                });
            }

            return verified(null, user);
        });
    });
};

passport.use(new localStrategy(verify));

passport.serializeUser((user, cb) => {
    cb(null, user._id);
});

passport.deserializeUser((id, cb) => {
    dbProvider.findById('user_accounts', id, (user) => {
        cb(null, user);
    });
});

module.exports = function (app, server) {
    app.engine('handlebars', handlebars.engine);
    app.set('view engine', 'handlebars');
    app.set('port', process.env.PORT || 3000);

    app.use(function (req, res, next) {
        // create a domain for this request
        var domain = require('domain').create();

        // handle errors on this domain
        domain.on('error', function (err) {
            console.error('DOMAIN ERROR CAUGHT\n', err.stack);

            try {
                // failsafe shutdown in 5 seconds
                setTimeout(function () {
                    console.error('Failsafe shutdown.');
                    process.exit(1);
                }, 5000);

                // disconnect from the cluster
                var worker = require('cluster').worker;

                if (worker) { worker.disconnect(); }

                // stop taking new requests
                server.close();

                try {
                    // attempt to use Express error route
                    next(err);
                } catch (err) {
                    // if Express error route failed, try plain Node response
                    console.error('Express error mechanism failed.\n', err.stack);
                    res.statusCode = 500;
                    res.setHeader('content-type', 'text/plain');
                    res.end('Server error.');
                }
            } catch (err) {
                console.error('Unable to send 500 response.\n', err.stack);
            }
        });

        // add the request and response object to the domain
        domain.add(req);
        domain.add(res);
        // execute the rest of the request chain in the domain
        domain.run(next);
    });

    // parse application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({ extended: false }));
    // parse application/json
    app.use(bodyParser.json());
    app.use(multer({ storage: storage }).single('photo'));
    app.use(require('cookie-parser')(appCredentials.cookieSecret));
    app.use(session({
        secret: appCredentials.cookieSecret,
        resave: false,
        saveUninitialized: false
    }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(require('csurf')({ cookie: true }));

    app.use(function(req, res, next) {
        res.locals._csrfToken = req.csrfToken();
        next();
    });

    app.use(express.static(__dirname + '/public'));

    app.use(function (req, res, next) {
        var cluster = require('cluster');

        if (cluster.isWorker) {
            console.log('Worker %d received request', cluster.worker.id);
        }

        next();
    });
};

routes.js

const passport = require('passport');
const main = require('./handlers/main.js');
const admin = require('./handlers/admin.js');

module.exports = function (app) {
    app.get('/', main.index);
    app.get('/home', main.index);
    app.get('/index', main.index);
    app.get('/about', main.about);
    app.get('/contact', main.contact);
    app.get('/shop', main.shop);
    app.get('/admin/products', admin.products);
    app.get('/admin/product/:id', admin.product);
    app.post('/admin/process-product', admin.processProduct);
    app.post('/admin/delete-product', admin.deleteProduct);
    app.get('/login', admin.login);
    app.get('/register', admin.register);
    app.get('/logout', admin.logout);
    app.post('/login', passport.authenticate('local', { failureRedirect: '/login' }), admin.postLogin);
    app.post('/register', admin.postRegister);
};

处理程序/ admin.js

// Load modules
const credential = require('credential')();
const dbProvider = require('../lib/db-provider.js');

module.exports.products = function products(req, res) {
    dbProvider.findAll('products', function (arr) {
        var newArr = [];

        arr.forEach(function (product, i) {
            newArr.push({
                index: i + 1,
                id: product._id,
                name: product.name
            });
        });

        res.render('products', { layout: 'admin', products: newArr });
    });
};

module.exports.product = function product(req, res) {
    var obj = { id: req.params.id };

    if (obj.id === 'new') {
        res.render('product', { layout: 'admin', context: obj });
    } else {
        dbProvider.findById('products', obj.id, function (result) {
            if (result !== null) {
                result.id = obj.id;
                res.render('product', { layout: 'admin', context: result });
            }
        });
    }
};

module.exports.processProduct = function processProduct(req, res) {
    var id = req.body.id;
    var name = req.body.name;
    var link = req.body.link;
    var file = req.file;
    var obj = {};

    if (id === 'new' || id === null || id === undefined) {
        if (!(name === null || name === undefined)) {
            obj.name = name;    
        }

        if (!(link === null || link === undefined)) {
            obj.link = link;    
        }

        if (!(file === null || file === undefined)) {
            var imgPath = file.path.slice(file.path.lastIndexOf('\img')).replace('\\', '\/');

            obj.filepath = imgPath;
        }

        dbProvider.insertOne('products', obj, function () {
            res.redirect(303, '/admin/products');
        });
    } else {
        dbProvider.findById('products', id, function (result) {
            if (result !== null) {
                if (!(name === null || name === undefined)) {
                    result.name = name;    
                }

                if (!(link === null || link === undefined)) {
                    result.link = link;
                }

                if (!(file === null || file === undefined)) {
                    var imgPath = file.path.slice(file.path.lastIndexOf('\img')).replace('\\', '\/');

                    result.filepath = imgPath;
                }

                dbProvider.replaceOne('products', id, result, false, function () {
                    res.redirect(303, '/admin/products');
                });
            } else {
                // error: couldn't update
            }
        });
    }
};

module.exports.deleteProduct = function deleteProduct(req, res) {
    var theId = req.body.theId;

    if (typeof theId === 'string') { // only one item (ie 1 id) is being deleted
         dbProvider.removeOneById('products', theId, function () {
            res.redirect(303, '/admin/products');
        });
    } else { // more than one item (ie an array of ids) are being deleted
        var i = 0;
        var end = theId.length;

        var fnAsyncLoop = function fnAsyncLoop(counter, stop, array, callback) {
            if (counter < stop) {
                dbProvider.removeOneById('products', array[counter], function () {
                    fnAsyncLoop(counter + 1, end, array, callback);
                });
            } else {
                callback();
            }
        };

        fnAsyncLoop(i, end, theId, function () {
            res.redirect(303, '/admin/products');
        });
    }
};

module.exports.login = (req, res) => {
        res.render('login', { layout: null});
};

module.exports.postLogin = function postLogin(req, res) {
    res.redirect('/');
};

module.exports.register = (req, res) => {
    res.render('register', { layout: null });
};

module.exports.postRegister = (req, res) => {
    const obj = {};

    credential.hash(req.body.password, (err, hash) => {
        if (err) { throw err; }

        obj.username = req.body.username;
        obj.hash = hash;

        dbProvider.insertOne('user_accounts', obj, () => {
            console.log('User created');

            res.redirect(303, '/');
        });
    });
};

module.exports.logout = (req, res) => {
    req.logout();
    res.redirect('/');
}

如果时间太长,我很抱歉。如果您需要进一步澄清,请告诉我。

问题是,任何人都可以看到我失踪的东西或我做错了什么吗?

0 个答案:

没有答案