未处理的承诺拒绝:发送后无法设置标头

时间:2017-07-15 07:37:19

标签: javascript node.js unit-testing header promise

我有一个这样的路由处理程序:

router.route('/callcenter/:callcenter_id/contactgroup/:contactgroup_id')
    .delete((req, res) => {
        if (typeof req.body.creator === 'undefined') {
            return res.status(400).json({
                success: false,
                error: { message: 'Invalid input' }
            });
        }
        const ContactGroup = new ContactGroupModel(db, req.params.callcenter_id, logger);
        ContactGroup.read(req.params.contactgroup_id)
            .then((result) => {
                if (!result) {
                    return res.status(404).json({
                        success: false,
                        error: { message: 'Contact group not found' }
                    });
                }
                if (req.body.creator !== result.creator) {
                    return res.status(400).json({
                        success: false,
                        error: { message: 'Invalid input' }
                    });
                }
                return ContactGroup.delete(req.params.contactgroup_id);
            })
            .then((result) => {
                if (!result) {
                    return res.status(404).json({
                        success: false,
                        error: { message: 'Contact group not found' }
                    });
                }
                return res.json({ success: true });
            })
            .catch((error) => res.status(400).json({
                success: false,
                error: { message: error }
            }));
    });

read的{​​{1}}和delete函数都是承诺。我写了几个测试:

ContactGroup

所有这些都通过,但记录器在最后两个包含describe('DELETE', () => { let id; beforeEach(() => ContactGroup.create(data).then((result) => id = result._id)); it('Should return 200 if successful', (done) => { chai.request(app) .delete('/callcenter/test/contactgroup/' + id) .send({ creator: 'user__1' }) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.success).to.equal(true); return done(); }); }); it('Should return 400 if input is invalid (without creator)', (done) => { chai.request(app) .delete('/callcenter/test/contactgroup/' + id) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 400 if input is invalid (unmatched creator)', (done) => { chai.request(app) .delete('/callcenter/test/contactgroup/' + id) .send({ creator: 'user__2' }) .end((err, res) => { expect(res.status).to.equal(400); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Invalid input'); return done(); }); }); it('Should return 404 if not found', (done) => { ContactGroup.delete(id).then( () => { chai.request(app) .delete('/callcenter/test/contactgroup/' + id) .send({ creator: 'user__1' }) .end((err, res) => { expect(res.status).to.equal(404); expect(res.body.success).to.equal(false); expect(res.body.error.message).to.equal('Contact group not found'); return done(); }); }); }); afterEach(() => ContactGroup.delete(id)); }); UnhandledPromiseRejectionWarning: Unhandled promise rejection

的测试中记录了一些警告

我还没知道为什么调用路由处理程序中的最终Can't set headers after they are sent块。我认为只有当promise函数被拒绝时,才会发生catch

1 个答案:

答案 0 :(得分:1)

您的代码尝试针对同一请求发送多个响应,这就是您收到“已发送标头”的消息的原因。

你有这样的代码:

ContactGroup.read(req.params.contactgroup_id).then(...).then(...).catch(...)

并且,有一些代码路径可以最终在这两个.then()处理程序中发送响应,从而导致该错误。在您的第一个.then()处理程序中,您似乎认为这样做:

return res.status(404).json(...)

停止承诺链。它不是。承诺链继续并直接进入下一个.then()处理程序。由于res.status()没有返回任何内容,因此它将转到下一个.then()处理程序,并将undefined作为已解析的值。那将导致你做:

return res.status(404).json(...)

会导致有关已发送标头的消息。

我不确定你想要的确切流程,但也许你想要这样的东西,你嵌套第二个.then(),所以当你以前做过return时它不会执行:

router.route('/callcenter/:callcenter_id/contactgroup/:contactgroup_id').delete((req, res) => {
    if (typeof req.body.creator === 'undefined') {
        return res.status(400).json({
            success: false,
            error: {
                message: 'Invalid input'
            }
        });
    }
    const ContactGroup = new ContactGroupModel(db, req.params.callcenter_id, logger);
    ContactGroup.read(req.params.contactgroup_id).then((result) => {
        if (!result) {
            return res.status(404).json({
                success: false,
                error: {
                    message: 'Contact group not found'
                }
            });
        }
        if (req.body.creator !== result.creator) {
            return res.status(400).json({
                success: false,
                error: {
                    message: 'Invalid input'
                }
            });
        }
        return ContactGroup.delete(req.params.contactgroup_id).then((result) => {
            if (!result) {
                return res.status(404).json({
                    success: false,
                    error: {
                        message: 'Contact group not found'
                    }
                });
            }
            return res.json({
                success: true
            });
        });
    }).catch((error) => res.status(400).json({
        success: false,
        error: {
            message: error
        }
    }));
});