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

726

Je suis assez nouveau sur Node.js et j'ai des 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 serai 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?

DjangoRocks
la source
réponse simple de visionmedia: github.com/visionmedia/express/issues/634
shi11i
2
Google m'a envoyé à cette question, mais les nouvelles versions d'ExpressJS ont un booléen res.headersSent qui peut être utilisé pour vérifier s'il est sûr de définir / envoyer des en
Julian Soro

Réponses:

1113

L' resobjet dans Express est une sous-classe de Node.jshttp.ServerResponse ( lire 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 qu'appeler res.write(data), et enfin 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 une fonction a essayé 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 qui sont appelés accidentellement deux fois ou toute erreur qui se produit après l'envoi du corps.

Dans votre cas, vous avez appelé res.redirect(), ce qui a provoqué la fin de la réponse. Ensuite, votre code a généré une erreur ( res.reqest null). et puisque l'erreur s'est produite au sein de votre réel function(req, res, next)(pas dans un rappel), Connect a pu l'attraper et a ensuite essayé d'envoyer une page d'erreur 500. Mais puisque les en-têtes ont déjà été envoyés, Node.js a setHeaderjeté l'erreur que vous avez vue.

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

La réponse doit être en tête et reste en tête :

  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; n'affecte que les méthodes spécifiques à Express)
  8. res.contentType(type) (Express uniquement)

La réponse doit être en tête et devient corps :

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

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

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

La réponse peut être dans l'une ou l'autre tête / corps et devient terminée :

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

La réponse peut être dans l'une ou l'autre tête / corps et reste dans son état actuel:

  1. res.addTrailers(headers)

La réponse doit être en tête et devient terminée :

  1. return next([err]) (Connect / Express uniquement)
  2. Toutes les exceptions 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)
yonran
la source
13
Oui, vérifiez d'appeler next () ou autre cb deux fois.
Tony Gutierrez
3
Les liens express semblent morts
Korhan Ozturk
25
attention également à cette erreur classique: res.redirect () n'arrête pas l'exécution des instructions ... alors revenez après. Sinon, un autre code pourrait être exécuté, ce qui pourrait provoquer involontairement la fameuse erreur d'en-tête. Merci pour l'explication!
KLoozen
C'est généralement une bonne idée d'utiliser le retour à la fin de votre rappel pour éviter cela
thethakuri
4
J'ai fait une très petite erreur dans mon middleware, je ne l'avais pas fait returnauparavant next(), merci cela m'a montré l'erreur!
illcrx
113

J'ai également rencontré cette erreur pendant un certain temps. Je pense (j'espère) que j'ai enroulé ma tête autour de lui, je voulais l'écrire ici pour référence.

Lorsque vous ajoutez un middleware pour vous connecter ou exprimer (qui est construit sur connect) à l'aide de la app.useméthode, vous ajoutez des éléments à Server.prototype.stackin connect (au moins avec le courant npm install connect, qui est très différent de celui de github à ce jour). Lorsque le serveur reçoit une demande, il parcourt la pile en appelant la (request, response, next)méthode.

Le problème est, si dans l'un des éléments du middleware écrit dans le corps de la réponse ou les en-têtes (il semble que ce soit / ou pour une raison quelconque), mais n'appelle pas response.end()et vous appeleznext() alors que la Server.prototype.handleméthode principale se termine, il va remarquer cette:

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

Donc, il jette une erreur. Mais l'erreur qu'il génère n'est que cette réponse de base (à partir du http.jscode source de connexion :

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

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

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

La façon dont tout doit être structuré est la suivante:

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 réponse sans appel response.end()ni appel next(), ce qui confond le serveur de connexion.

Lance Pollard
la source
7
+1 Ceci est une excellente explication, mais qu'en est-il du cas lorsque vous utilisez res.redirect ()? Je rencontre fréquemment ce problème lorsque le middleware tente de rediriger en fonction d'une condition. Le middleware ne devrait-il pas rediriger, selon votre exemple de «bon middleware»?
qodeninja
Vous savez que j'ai ce problème exact en raison de ce que vous appelez un middleware problématique, mais j'ai besoin d'un cas dans lequel je renvoie une réponse mais j'aimerais effectuer un traitement supplémentaire dans un contrôleur séparé dans le cadre de la chaîne, comment dois-je faire pour supprimer cette erreur ?
iQ.
57

Certaines des réponses à cette Q&R sont fausses. La réponse acceptée n'est pas non plus très "pratique", donc je veux poster une réponse qui explique les choses en termes plus simples. Ma réponse couvrira 99% des erreurs que je vois publiées maintes et maintes fois. Pour les raisons réelles de l'erreur, jetez un œil à la réponse acceptée.


HTTP utilise un cycle qui nécessite une réponse par demande. Lorsque le client envoie une demande (par exemple POST ou GET), le serveur ne doit lui renvoyer qu'une seule réponse.

Ce message d'erreur:

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

se produit généralement lorsque vous envoyez plusieurs réponses pour une demande. Assurez-vous que les fonctions suivantes sont appelées une seule fois par demande:

  • res.json()
  • res.send()
  • res.redirect()
  • res.render()

(et quelques autres qui sont rarement utilisés, vérifiez la réponse acceptée)

Le rappel d'itinéraire ne reviendra pas lorsque ces fonctions res seront appelées. Il continuera à fonctionner jusqu'à ce qu'il atteigne la fin de la fonction ou une instruction de retour. Si vous souhaitez revenir lors de l' envoi d' une réponse , vous pouvez le faire comme si: return res.send().


Prenons par exemple ce code:

app.post('/api/route1', function(req, res) {
  console.log('this ran');
  res.status(200).json({ message: 'ok' });
  console.log('this ran too');
  res.status(200).json({ message: 'ok' });
}

Lorsqu'une demande POST est envoyée à / api / route1, elle exécutera chaque ligne du rappel. Un message d'erreur Impossible de définir les en-têtes après leur envoi sera lancé car il res.json()est appelé deux fois, ce qui signifie que deux réponses sont envoyées.

Une seule réponse peut être envoyée par demande!


L'erreur dans l'exemple de code ci-dessus était évidente. Un problème plus typique est lorsque vous avez plusieurs branches:

app.get('/api/company/:companyId', function(req, res) {
  const { companyId } = req.params;
  Company.findById(companyId).exec((err, company) => {
      if (err) {
        res.status(500).json(err);
      } else if (!company) {
        res.status(404).json();      // This runs.
      }
      res.status(200).json(company); // This runs as well.
    });
}

Cette route avec rappel associé trouve une entreprise dans une base de données. Lorsque vous effectuez une requête pour une entreprise qui n'existe pas, nous allons entrer dans la else ifsuccursale et envoyer une réponse 404. Après cela, nous allons passer à la prochaine déclaration qui envoie également une réponse. Maintenant, nous avons envoyé deux réponses et le message d'erreur se produira. Nous pouvons corriger ce code en nous assurant de n'envoyer qu'une seule réponse:

.exec((err, company) => {
  if (err) {
    res.status(500).json(err);
  } else if (!company) {
    res.status(404).json();         // Only this runs.
  } else {
    res.status(200).json(company);
  }
});

ou en revenant lors de l'envoi de la réponse:

.exec((err, company) => {
  if (err) {
    return res.status(500).json(err);
  } else if (!company) {
    return res.status(404).json();  // Only this runs.
  }
  return res.status(200).json(company);
});

Un gros pécheur est les fonctions asynchrones. Prenez la fonction de cette question, par exemple:

article.save(function(err, doc1) {
  if (err) {
    res.send(err);
  } else {
    User.findOneAndUpdate({ _id: req.user._id }, { $push: { article: doc._id } })
    .exec(function(err, doc2) {
      if (err) res.send(err);
      else     res.json(doc2);  // Will be called second.
    })

    res.json(doc1);             // Will be called first.
  }
});

Ici, nous avons une fonction asynchrone ( findOneAndUpdate()) dans l'exemple de code. S'il n'y a pas d'erreur, ( err) findOneAndUpdate()sera appelé. Comme cette fonction est asynchrone, res.json(doc1)elle sera appelée immédiatement. Supposons qu'il n'y ait aucune erreur dans findOneAndUpdate(). Le res.json(doc2)dans le elsesera alors appelé. Deux réponses ont maintenant été envoyées et le message d'erreur Can't set headers s'affiche.

La solution, dans ce cas, serait de supprimer le fichier res.json(doc1). Pour renvoyer les deux documents au client, le res.json()dans l'autre peut être écrit comme res.json({ article: doc1, user: doc2 }).

Mika Sundland
la source
2
Vous êtes à l'intérieur d'une fonction asynchrone et devez return leres.json
Genovo
Mon problème utilisait la res.sendboucle in for.
Maihan Nijat
1
Cela m'a aidé à la fin à comprendre et à résoudre le problème, merci beaucoup :)
Pankaj Parkar
merci beaucoup, vous économisez mon temps.
Mohammad Faisal
C'est définitivement la meilleure réponse!
Juanma Menendez
53

J'ai eu ce même problème et j'ai réalisé que c'était parce que j'appelais res.redirectsans returndéclaration, donc la nextfonction était également appelée immédiatement après:

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

Ce qui aurait dû être:

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

Beaucoup de gens ont rencontré cette erreur. C'est une confusion avec le traitement asynchrone. Très probablement, une partie de votre code définit des en-têtes dans le premier tick, puis vous exécutez un rappel asynchrone 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) essaient d'ajouter des en-têtes supplémentaires, mais il est trop tard car l'en-tête de réponse a déjà été transmis.

Je ne sais pas exactement ce qui cause votre erreur, mais considérez les rappels comme des domaines potentiels à étudier.

Une astuce simple pour simplifier votre code. Débarrassez-vous app.configure()et appelez simplement app.usedirectement dans votre portée de niveau supérieur.

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

Peter Lyons
la source
Une redirection 30X est un code de réponse HTTP. w3.org/Protocols/rfc2616/rfc2616-sec10.html Les codes 300-399 sont différentes variantes de redirection, 302 et 301 étant couramment utilisés pour envoyer le client vers une autre URL. Lorsque vous effectuez response.redirect (...) dans le noeud, un en-tête de redirection 30X sera envoyé dans la réponse.
Peter Lyons
3
Ohhhh. J'imaginais 30 redirections d'affilée ou quelque chose comme ça
Janac Meena
17

J'ai fait bouillir ma tête sur ce problème et cela s'est produit en raison d'une erreur imprudente dans la gestion des rappels. les rappels non retournés provoquent la définition de la réponse deux fois.!

Mon programme avait un code qui valide la demande 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 se poursuit 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 est le suivant: la validation Incase échoue, le rappel est appelé et la réponse est définie. Mais pas retourné. Il continue donc la méthode passe à db et a réussi / échoué. Il appelle à nouveau le même rappel, ce qui entraîne la définition de la réponse deux fois maintenant.

La solution est donc 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éfinir une fois l'objet de réponse

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);
hasard
la source
1
Merci! Cela s'est avéré être mon problème aussi. Je viens de faire un ctrl + f et j'ai trouvé un callback(...)sans un return;après qui a finalement été res.send(...)appelé deux fois.
15

Vous obtiendrez ce type d'erreur lorsque vous passerez des instructions après avoir envoyé une réponse.

Par exemple:

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

Cela entraînera l'erreur que vous voyez, car une fois la réponse envoyée, ce qui suit res.sendne sera pas exécuté.

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

troyen
la source
C'était mon problème exact :)
Joel Balmer
6

Parfois, vous pouvez obtenir 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 dans votre fonction. Remarque: ici next () signifie qu'après avoir répondu au client avec votre réponse ( c'est-à-dire res.send ou res.end ), vous essayez toujours d'exécuter du code pour répondre à nouveau, ce n'est donc pas légal.

Exemple :

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

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

Surendra Parchuru
la source
6

Si vous utilisez des fonctions de rappel, utilisez returnaprès le errbloc. Il s'agit de 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 Node v10.16.0et express4.16.4

Krishnadas PC
la source
4

Cette erreur se produit lorsque vous envoyez 2 réponses. Par exemple :

if(condition A)
{ 

      res.render('Profile', {client:client_});

}

if (condition B){

      res.render('Profile', {client:client_});
    }
  }

Imaginez si pour une raison quelconque les conditions A et B sont vraies, rendervous obtiendrez cette erreur dans la seconde

Badr Bellaj
la source
3

Dans mon cas, c'était une réponse 304 (mise en cache) qui causait le problème.

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/

mélangé
la source
Dans mon cas également 304 réponses. J'utilise des fibres pour le traitement. De toute façon, votre réponse aide beaucoup. merci
Dileep stanley
Quelqu'un peut-il expliquer les implications de la suppression de l'en-tête etag?
mattwilsn
2
Les ETags permettent au serveur de ne pas envoyer de contenu qui n'a pas changé. La désactiver désactive cette fonction. L'entrée wikipedia ETag ( en.wikipedia.org/wiki/HTTP_ETag ) a une explication plus longue.
blended
3

Dans mon cas, cela s'est produit avec React et postal.js lorsque je ne me suis pas désabonné d'une chaîne dans le componentWillUnmountrappel de mon composant React.

Zoltán
la source
2

Pour tous ceux qui arrivent à cela et aucune des autres solutions n'a aidé, dans mon cas, cela s'est manifesté sur un itinéraire qui a géré le téléchargement d'images mais n'a pas géré les délais d'attente , et donc si le téléchargement a pris trop de temps et a expiré, lorsque le rappel a été déclenché après l'envoi de la réponse de délai d'attente , l'appel à res.send () a entraîné le blocage, car les en-têtes étaient déjà définis pour tenir compte du délai d'attente.

Cela a été facilement reproduit en définissant un délai très court et en frappant l'itinéraire avec une image assez grande, le crash a été reproduit à chaque fois.

Mike
la source
1
comment avez-vous géré le délai d'attente pour éviter cela?
2

Je penchais juste ç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();
});
Adam Boostani
la source
2

Ajoutez ce logiciel intermédiaire 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();
});
ASHISH RANJAN
la source
2

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

Ankit Manchanda
la source
1

J'ai eu ce problème lorsque je faisais des promesses de nidification. Une promesse à l'intérieur d'une promesse retournerait 200 au serveur, mais l'instruction catch de la promesse externe retournerait 500. Une fois que j'ai corrigé cela, le problème a disparu.

rharding
la source
comment avez-vous réglé cela? J'ai le même problème avec les promesses. Je ne peux pas éviter de les imbriquer ... alors comment arrêter l'exécution à la déclaration de retour?
saurabh
1

Venu ici de nuxt , le problème était dans la asyncDataméthode du composant , j'ai oublié de returnpromettre qui récupérait les données et y mettait l'en-tête.

Nick Synev
la source
1

Veuillez vérifier si votre code renvoie plusieurs instructions res.send () pour une seule demande. Comme quand j'ai eu ce problème ...

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

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

Je manipulais différents cas en utilisant switch sans interruption d'écriture. Pour ceux qui ne sont pas familiers avec les commutateurs, sachez que sans interruption, renvoyez des mots clés. Le code sous case et les lignes suivantes seront exécutés quoi qu'il arrive. Donc, même si je veux envoyer un seul res.send, en raison de cette erreur, il renvoyait plusieurs instructions res.send, ce qui a incité

erreur ne peut pas définir 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; }

KNDheeraj
la source
merci pour votre inspiration la même chose m'est arrivée. Je l'ai résolu aussi avec else if condition.
Amr AbdelRahman
1

Il est très probable que ce soit plus un problème de nœud, 99% du temps, c'est un double rappel qui vous fait répondre deux fois, ou deux fois () suivant, etc., sacrément sûr. Il a résolu mon problème en utilisant next () dans une boucle. Supprimez le suivant () de la boucle ou arrêtez de l'appeler plus d'une fois.

Naved Ahmad
la source
1

J'ajoute simplement le mot clé de retour comme: return res.redirect("/great");et walla!

Emmanuel Benson
la source
1

J'ai eu le même problème causé par la mangouste.

pour corriger cela, vous devez activer Promises, afin que vous puissiez ajouter: mongoose.Promise = global.Promiseà votre code, ce qui permet d'utiliser native js promises.

d'autres alternatives à cette solution sont:

var mongoose = require('mongoose');
// set Promise provider to bluebird
mongoose.Promise = require('bluebird');

et

// q
mongoose.Promise = require('q').Promise;

mais vous devez d'abord installer ces packages.

sina
la source
1

erreur trouver par lui-même après un RND:

1) mon code d'erreur:

return res.sendStatus(200).json({ data: result });

2) mon code de réussite

return res.status(200).json({ data: result });

la différence est que j'ai utilisé sendStatus () au lieu de status () .

nagender pratap chauhan
la source
0

Dans Typescript, mon problème était que je n'ai 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 
});
Janac Meena
la source
0

Si vous ne recevez pas d'aide d'en haut: pour les noobs La raison de cette erreur est d'envoyer la demande plusieurs fois, comprenons dans 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 le ci-dessus, appeler next () deux fois soulèvera 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);* }) })

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

Sanjay
la source
0

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

M. Ratnadeep
la source
0

Mon problème était que j'avais un setIntervalfonctionnement, qui avait un if/elsebloc, où la clearIntervalméthode était à l'intérieur du else:

      const dataExistsInterval = setInterval(async () => {
        const dataExists = Object.keys(req.body).length !== 0;
        if (dataExists) {
          if (!req.files.length) {
            return res.json({ msg: false });
          } else {
              clearInterval(dataExistsInterval);
            try {
            . . .

Mettre l' clearIntervalavant avant a if/elsefait l'affaire.

Mike K
la source
0

Dans mon cas, dans une boucle, je mets res.render()donc aurait pu être tenté d'appeler plusieurs fois.

Hasan Sefa Ozalp
la source
-1

Tout ce que j'avais à faire en cas de cette erreur était res.end ().

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

L'autre problème que vous pourriez rencontrer est qu'il y a du 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 
};
codeur
la source