0

I use supertest to test my RESTful API which develop by express, but I encountered a problem. The following the debug message.

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
    at ServerResponse.header \nodejs-framework\node_modules\express\lib\response.js:719:10)
    at ServerResponse.send \nodejs-framework\node_modules\express\lib\response.js:164:12)
    at done \nodejs-framework\node_modules\express\lib\response.js:956:10)
    at View.exports.renderFile [as engine] \nodejs-framework\node_modules\ejs\lib\ejs.js:355:10)
    at View.render \nodejs-framework\node_modules\express\lib\view.js:126:8)
    at tryRender \nodejs-framework\node_modules\express\lib\application.js:639:10)
    at EventEmitter.render \nodejs-framework\node_modules\express\lib\application.js:591:3)
    at ServerResponse.render \nodejs-framework\node_modules\express\lib\response.js:960:7)
    at D:\H60\H60_New\nodejs-framework\app.js:216:13
    at Layer.handle_error \nodejs-framework\node_modules\express\lib\router\layer.js:71:5)
    at trim_prefix \nodejs-framework\node_modules\express\lib\router\index.js:310:13)
    at D:\H60\H60_New\nodejs-framework\node_modules\express\lib\router\index.js:280:7
    at Function.process_params \nodejs-framework\node_modules\express\lib\router\index.js:330:12)
    at next \nodejs-framework\node_modules\express\lib\router\index.js:271:10)
    at D:\H60\H60_New\nodejs-framework\node_modules\express\lib\router\index.js:618:15
    at IncomingMessage.next \nodejs-framework\node_modules\express\lib\router\index.js:256:14)
    at done \nodejs-framework\node_modules\express\lib\response.js:955:25)
    at tryRender \nodejs-framework\node_modules\express\lib\application.js:641:5)
    at EventEmitter.render \nodejs-framework\node_modules\express\lib\application.js:591:3)

When I use supertest.agent(envFile.API_SERVER.url) as test target, it will pass forever,

but while I use supertest.agent(envFile.API_SERVER.app) which is a enter point in my project, it will be failed when I need to respond in middleware.

The following, is my code in my middleware.

let paramObj = {
        account: -1,
        pw: -2,
        email: -3,
    }, 
    paramObjKey = Object.keys(paramObj);

for ( let param of paramObjKey ) {
    if ( typeof req.body[param] === "undefined" ) {
        res.json(paramObj[param]);
        return;
    } 
}
next();

I have another middleware which will handle exceptions, and it is the root cause in this problem. It will respond again after the previous middleware has responded.

app.use(function(err, req, res, next) {
    if ( !typeService.isNull(err) ) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    }
});
J. Q
  • 1

2 Answers2

0

You can't send responses multiple times.

Having res.json(paramObj[param]); inside a for loop sends a response each iteration.

You need to send the response only once.

Swaraj Giri
  • 4,007
  • 2
  • 27
  • 44
  • I think it will be returned, when it find the first missing parameter. I have tried it in https://codepen.io/anon/pen/KNeJWj – J. Q Dec 09 '16 at 01:06
0

I agree w/ @Swaraj.

Change the return in your for loop to break instead.

let paramObj = {
    account: -1,
    pw: -2,
    email: -3,
}, 
paramObjKey = Object.keys(paramObj);

for ( let param of paramObjKey ) {
    if ( typeof req.body[param] === "undefined" ) {
        res.json(paramObj[param]);
        break;
    } 
}
next();

This will break out of the for loop and execute the next link in the middleware chain.

a11smiles
  • 1,190
  • 1
  • 9
  • 21