web-dev-qa-db-fra.com

Erreur: Impossible de définir les en-têtes après leur envoi au client.

Je suis assez nouveau sur Node.js et j'ai quelques problèmes.

J'utilise Node.js 4.10 et Express 2.4.3.

Lorsque j'essaie d'accéder à http://127.0.0.1:8888/auth/facebook , je suis redirigé vers http://127.0.0.1:8888/auth/facebook_callback .

J'ai ensuite reçu l'erreur suivante:

Error: Can't render headers after they are sent to the client.
    at ServerResponse.<anonymous> (http.js:573:11)
    at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
    at ServerResponse.writeHead (http.js:813:20)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
    at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
    at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
    at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
    at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
    at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
    at EventEmitter._tickCallback (node.js:126:26)

Voici mon code:

var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"

var cookieSecret = "node";     // enter a random hash for security

var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();


app.configure(function(){
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({secret: cookieSecret}));
    app.use(auth([
        auth.Facebook({
            appId : fbId,
            appSecret: fbSecret,
            callback: fbCallbackAddress,
            scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
            failedUri: '/noauth'
        })
    ]));
    app.use(app.router);
});


app.get('/auth/facebook', function(req, res) {
  req.authenticate("facebook", function(error, authenticated) {
    if (authenticated) {
      res.redirect("/great");
      console.log("ok cool.");
      console.log(res['req']['session']);
    }
  });
});

app.get('/noauth', function(req, res) {
  console.log('Authentication Failed');
  res.send('Authentication Failed');
});

app.get('/great', function( req, res) {
  res.send('Supercoolstuff');
});

app.listen(8888);

Puis-je savoir ce qui ne va pas avec mon code?

516
DjangoRocks

L'objet res dans Express est une sous-classe de Node.js http.ServerResponse ( lit la source http.js ). Vous êtes autorisé à appeler res.setHeader(name, value) aussi souvent que vous le souhaitez jusqu'à ce que vous appeliez res.writeHead(statusCode). Après writeHead, les en-têtes sont intégrés et vous ne pouvez appeler que res.write(data), et finalement res.end(data).

L'erreur "Erreur: impossible de définir les en-têtes après leur envoi". signifie que vous êtes déjà dans l'état Body ou Finished, mais certaines fonctions ont tenté de définir un en-tête ou un statusCode. Lorsque vous voyez cette erreur, essayez de rechercher tout ce qui tente d'envoyer un en-tête après qu'une partie du corps a déjà été écrite. Par exemple, recherchez les rappels appelés accidentellement deux fois ou toute erreur survenant après l'envoi du corps.

Dans votre cas, vous avez appelé res.redirect(), ce qui a provoqué le passage de la réponse à Terminé. Ensuite, votre code a généré une erreur (res.req est null). et puisque l'erreur s'est produite dans votre function(req, res, next) (pas dans un rappel), Connect a été en mesure de la détecter et a ensuite essayé d'envoyer une page d'erreur 500. Mais comme les en-têtes ont déjà été envoyés, la variable setHeader de Node.js a lancé l'erreur que vous avez constatée.

Liste complète des méthodes de réponse Node.js/Express et indication du moment où elles doivent être appelées:

La réponse doit être dans Head et reste dans Head:

  1. res.writeContinue()
  2. res.statusCode = 404
  3. res.setHeader(name, value)
  4. res.getHeader(name)
  5. res.removeHeader(name)
  6. res.header(key[, val]) (Express uniquement)
  7. res.charset = 'utf-8' (Express uniquement; affecte uniquement les méthodes spécifiques à Express)
  8. res.contentType(type) (Express uniquement)

La réponse doit être dans Head et devient Body:

  1. res.writeHead(statusCode, [reasonPhrase], [headers])

La réponse peut être soit tête/corps et reste dans corps:

  1. res.write(chunk, encoding='utf8')

La réponse peut être soit Head/Body et devient Finished:

  1. res.end([data], [encoding])

La réponse peut être soit Head/Body et reste dans son état actuel:

  1. res.addTrailers(headers)

La réponse doit être dans Head et devient Finished:

  1. return next([err]) (Connect/Express uniquement)
  2. Toute exception dans le middleware function(req, res, next) (Connect/Express uniquement)
  3. res.send(body|status[, headers|status[, status]]) (Express uniquement)
  4. res.attachment(filename) (Express uniquement)
  5. res.sendfile(path[, options[, callback]]) (Express uniquement)
  6. res.json(obj[, headers|status[, status]]) (Express uniquement)
  7. res.redirect(url[, status]) (Express uniquement)
  8. res.cookie(name, val[, options]) (Express uniquement)
  9. res.clearCookie(name[, options]) (Express uniquement)
  10. res.render(view[, options[, fn]]) (Express uniquement)
  11. res.partial(view[, options]) (Express uniquement)
840
yonran

J'ai aussi rencontré cette erreur pendant un moment. Je pense (espère) que je l'ai compris dans ma tête et que je voulais l'écrire ici pour référence.

Lorsque vous ajoutez un middleware à connect ou express (basé sur connect) à l’aide de la méthode app.use, vous ajoutez des éléments à Server.prototype.stack dans connect (Au moins avec le npm install connect actuel, qui est assez différent de le seul github à partir de ce post). Lorsque le serveur reçoit une demande, il effectue une itération sur la pile en appelant la méthode (request, response, next).

Le problème est que si l'un des éléments du middleware écrit dans le corps de la réponse ou dans des en-têtes (il semble que ce soit/ou pour une raison quelconque), mais n'appelle pas response.end() et vous appelez next(), puis en tant que Server.prototype.handle central. méthode terminée, il va remarquer que:

  1. il n'y a plus d'articles dans la pile, et/ou
  2. ce response.headerSent est vrai.

Donc, ça jette une erreur. Mais l’erreur qu’elle génère est juste cette réponse de base (du code source connect http.js:

res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);

Ici, il appelle res.setHeader('Content-Type', 'text/plain');, que vous avez probablement défini dans votre méthode render, sans appeler response.end (), quelque chose comme:

response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");

Voici comment tout doit être structuré:

Bon middleware

// middleware that does not modify the response body
var doesNotModifyBody = function(request, response, next) {
  request.params = {
    a: "b"
  };
  // calls next because it hasn't modified the header
  next();
};

// middleware that modify the response body
var doesModifyBody = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  response.end();
  // doesn't call next()
};

app.use(doesNotModifyBody);
app.use(doesModifyBody);

Middleware problématique

var problemMiddleware = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  next();
};

Le middleware problématique définit l'en-tête de la réponse sans appeler response.end() et appelle next(), ce qui confond le serveur de connect.

80
Lance Pollard

J'ai eu le même problème et je me suis rendu compte que c'était parce que j'appelais res.redirect sans instruction return. La fonction next était également appelée immédiatement après:

auth.annonymousOnly = function(req, res, next) {
    if (req.user) res.redirect('/');
    next();
};

Qui aurait dû être:

auth.annonymousOnly = function(req, res, next) {
    if (req.user) return res.redirect('/');
    next();
};
37
ergusto

Beaucoup de gens ont frappé cette erreur. Cela confond avec le traitement asynchrone. Il est fort probable que certains de votre code définissent des en-têtes lors du premier tick, puis vous exécutez un rappel async dans un tick futur. Entre les deux, l'en-tête de réponse est envoyé, mais d'autres en-têtes (comme une redirection 30X) tentent d'ajouter des en-têtes supplémentaires, mais il est trop tard, l'en-tête de réponse ayant déjà été transmis.

Je ne sais pas exactement ce qui cause votre erreur, mais examinez les rappels en tant que domaines potentiels sur lesquels enquêter.

Un conseil simple pour simplifier votre code. Débarrassez-vous de app.configure() et appelez simplement app.use directement dans votre écran de premier niveau.

Voir aussi le module everyauth , qui utilise Facebook et une douzaine d’autres fournisseurs d’authentification tiers.

32
Peter Lyons

J'ai fait bouillir la tête à ce sujet et cela est dû à une erreur d'inattention dans la gestion des rappels. Les callbacks non retournés font que la réponse soit définie deux fois.

Mon programme avait un code qui valide la requête et interroge la base de données. après avoir validé s'il y avait une erreur, je rappelais index.js avec les erreurs de validation. Et si la validation réussit, elle continue et frappe la base de données avec succès/échec. 

    var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
   else
    some code 
    callback(null, success);

Ce qui se passait, c'est que: la validation de casse échoue, le rappel est appelé et la réponse est définie. Mais pas retourné. Donc, il continue toujours la méthode va à la base de données et frappe le succès/échec. Il appelle à nouveau le même rappel, ce qui a pour effet de définir deux fois la réponse. 

Donc, la solution est simple, vous devez "renvoyer" le rappel pour que la méthode ne continue pas à s'exécuter, une fois que l'erreur s'est produite, et donc définit l'objet de réponse une fois 

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);
14
randomness

Ce type d'erreur que vous obtiendrez lorsque vous passerez des déclarations après avoir envoyé une réponse.

Par exemple: 

res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");

L'erreur que vous voyez entraînera, car une fois la réponse envoyée, le res.send suivant ne sera pas exécuté.

Si vous voulez faire quelque chose, vous devriez le faire avant d'envoyer la réponse.

13
Trojan

Parfois, vous pouvez avoir cette erreur lorsque vous essayez d’appeler la fonction next () après res.end ou res.send , essayez de supprimer si vous avez next () après res.send ou res.end in votre fonction . Remarque: ici next () signifie que, après avoir répondu au client avec votre réponse ( c.-à-d. res.send ou res.end ), vous essayez toujours d'exécuter du code pour répondre à nouveau, donc ce n'est pas légal.

Exemple : 

router.get('/',function (req,res,next){
     res.send("request received");
     next(); // this will give you the above exception 
});

retirez next() de la fonction ci-dessus et cela fonctionnera.

5

Dans mon cas, c'était une réponse 304 (mise en cache) qui était à l'origine du problème. 

La solution la plus simple:

app.disable('etag');

Solution alternative ici si vous voulez plus de contrôle:

http://vlasenko.org/2011/10/12/expressconnect-static-set-last-modified-to-now-to-avoid-304-not-modified/

3
blented

Dans mon cas, cela s'est produit avec React et postal.js lorsque je ne me suis pas désabonné d'un canal dans le rappel componentWillUnmount de mon composant React.

3
Zoltán

Juste penché ça. Vous pouvez transmettre les réponses via cette fonction:

app.use(function(req,res,next){
  var _send = res.send;
  var sent = false;
  res.send = function(data){
    if(sent) return;
    _send.bind(res)(data);
    sent = true;
};
  next();
});
2
iMad

Pour ceux qui s'y intéressent et aucune autre solution ne m'a aidé, dans mon cas, cela s'est manifesté sur un itinéraire qui gère le téléchargement des images mais ne gère pastimeouts, et donc si le téléchargement prend trop de temps et expiré, lorsque le rappel a été déclenché après l'envoi de la réponse de délai d'attente, l'appel de res.send () a provoqué le blocage, car les en-têtes étaient déjà configurés pour prendre en compte le délai d'attente.

Cela a été facilement reproduit en définissant un délai très court et en parcourant la route avec une image de taille décente, le crash a été reproduit à chaque fois.

2
Mike

Ajoutez ce middleware et cela fonctionnera

app.use(function(req,res,next){
 var _send = res.send;
var sent = false;
res.send = function(data){
    if(sent) return;
    _send.bind(res)(data);
    sent = true;
};
next();
});
2
ASHISH RANJAN

Cela se produit lorsque la réponse a été transmise au client et que vous tentez à nouveau de donner une réponse. Vous devez vérifier dans votre code que vous retournez à nouveau quelque part la réponse au client, ce qui provoque cette erreur. Vérifiez et renvoyez la réponse une fois quand vous voulez revenir.

2
Ankit Manchanda

Venu ici de nuxt , le problème venait de la méthode asyncData du composant, j'ai oublié de return promise qui récupérait des données et définissait l'en-tête.

1
Nick Synev

Mon problème avec TypeScript était que je n’avais pas fermé la connexion websocket après avoir reçu un message.

WebSocket.on("message", (data) => {
    receivedMessage = true;
    doSomething(data);
    localSocket.close(); //This close the connection, allowing 
});
0
Janac Meena

Si vous utilisez des fonctions de rappel, utilisez return après le bloc err. C'est l'un des scénarios dans lesquels cette erreur peut se produire.

userModel.createUser(data, function(err, data) {
    if(err) {
      res.status = 422
      res.json(err)
      return // without this return the error can happen.
    }
    return res.json(data)
  })

Testé sur la version de noeud v10.16.0 et express 4.16.4

0
Krishnadas PC

En cas d'erreur, tout ce que j'avais à faire était res.end ().

 auth.annonymousOnly = function(req, res, next) {
 // add other task here   
   res.end();    
  };

L'autre problème auquel vous pourriez être confronté est qu'il existe un code après res.json et res. écrire. Dans ce cas, vous devez utiliser return pour arrêter l'exécution après cela.

 auth.annonymousOnly = function(req, res, next) {

  if(!req.body.name)
  {
    res.json({error:"some error"});
    return;
  }
  let comp = "value"; // this is the code after res.json which may cause some problems so you have to use return 
};
0
coder

J'ai eu ce problème quand je faisais nid de promesses. Une promesse à l'intérieur d'une promesse renverrait 200 sur le serveur, mais l'instruction de capture de la promesse extérieure renverrait un 500. Une fois que j'ai résolu ce problème, le problème a disparu.

0
Ross Harding

Dans mon cas, cela se produit en raison de plusieurs rappels. J'ai appelé la méthode next() plusieurs fois au cours du code 

0
Mr. Ratnadeep

Vérifiez si votre code renvoie plusieurs instructions res.send () pour une seule demande. Comme quand j'avais ce problème ...

J'étais ce problème dans mon application de noeud Restify. L'erreur était que 

switch (status) { case -1: res.send(400); case 0: res.send(200); default: res.send(500); }

Je m'occupais de divers cas en utilisant switch sans écriture. Pour ceux qui connaissent peu le boîtier de commutation, sachez que, sans pause, renvoyez les mots-clés. Le code sous la casse et les lignes suivantes seront exécutés quoi qu'il arrive. Donc, même si je veux envoyer res.send unique, à cause de cette erreur, il retournait plusieurs instructions res.send, ce qui invitait 

error cant définit les en-têtes après leur envoi au client. Ce qui a été résolu en ajoutant ceci ou en utilisant return avant chaque méthode res.send () comme return res.send (200)

switch (status) { case -1: res.send(400); break; case 0: res.send(200); break; default: res.send(500); break; }

0
KNDheeraj

Il est très probable qu'il s'agisse davantage d'un nœud. Dans 99% des cas, il s'agit d'un double rappel qui vous oblige à répondre deux fois, ou à deux reprises, etc. Il a résolu mon problème en utilisant next () dans une boucle. Supprimez next () de la boucle ou arrêtez de l'appeler plus d'une fois.

0
Naved Ahmad

Si vous ne recevez pas d’aide d’en haut: pour les noobs La raison de cette erreur est l’envoi de demandes à plusieurs reprises, laissez-nous comprendre certains cas: - 1. ` 

module.exports = (req,res,next)=>{
        try{
           const decoded  = jwt.verify(req.body.token,"secret");
           req.userData = decoded;
           next();
        }catch(error){
            return res.status(401).json({message:'Auth failed'});
        }
        next();   
        }

` dans l'appel ci-dessus next () à deux reprises va générer une erreur

  1. router.delete('/:orderId', (req, res, next) => { Order.remove({_id:req.params.orderId},(err,data)=>{ if(err){ **res.status(500).json(err);** }else{ res.status(200).json(data); } *res.status(200).json(data);* }) })

répondre ici est envoyer deux fois vérifier si vous avez déjà envoyé une réponse

0
Sanjay