Fehler: Header können nicht festgelegt werden, nachdem sie an den Client gesendet wurden

724

Ich bin ziemlich neu bei Node.js und habe einige Probleme.

Ich verwende Node.js 4.10 und Express 2.4.3.

Wenn ich versuche, auf http://127.0.0.1:8888/auth/facebook zuzugreifen , werde ich zu http://127.0.0.1:8888/auth/facebook_callback weitergeleitet .

Ich habe dann folgenden Fehler erhalten:

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)

Folgendes ist mein 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);

Darf ich wissen, was mit meinem Code nicht stimmt?

DjangoRocks
quelle
einfache Antwort von visionmedia: github.com/visionmedia/express/issues/634
shi11i
2
Google hat mich zu dieser Frage geschickt, aber neuere Versionen von ExpressJS haben res.headersSent Boolean, mit dem überprüft werden kann, ob das Setzen / Senden von Headern sicher ist
Julian Soro

Antworten:

1112

Das resObjekt in Express ist eine Unterklasse von Node.jshttp.ServerResponse ( lesen Sie die http.js-Quelle ). Sie können res.setHeader(name, value)so oft anrufen, wie Sie möchten, bis Sie anrufen res.writeHead(statusCode). Danach writeHeadwerden die Header eingebrannt und Sie können nur noch anrufen res.write(data)und schließlich res.end(data).

Der Fehler "Fehler: Header können nach dem Senden nicht festgelegt werden." bedeutet, dass Sie sich bereits im Status "Körper" oder "Fertig" befinden, aber eine Funktion versucht hat, einen Header oder Statuscode festzulegen. Wenn Sie diesen Fehler sehen, versuchen Sie, nach etwas zu suchen, das versucht, einen Header zu senden, nachdem ein Teil des Körpers bereits geschrieben wurde. Suchen Sie beispielsweise nach Rückrufen, die versehentlich zweimal aufgerufen werden, oder nach Fehlern, die nach dem Senden des Körpers auftreten.

In Ihrem Fall haben Sie angerufen res.redirect(), wodurch die Antwort beendet wurde. Dann hat Ihr Code einen Fehler ausgelöst ( res.reqist null). und da der Fehler innerhalb Ihres tatsächlichen function(req, res, next)(nicht innerhalb eines Rückrufs) aufgetreten ist, konnte Connect ihn abfangen und versuchte dann, eine 500-Fehler-Seite zu senden. Da die Header jedoch bereits gesendet wurden, hat Node.js setHeaderden Fehler ausgelöst, den Sie gesehen haben.

Umfassende Liste der Node.js / Express-Antwortmethoden und wann sie aufgerufen werden müssen:

Die Antwort muss im Kopf sein und bleibt im Kopf :

  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]) (Nur Express)
  7. res.charset = 'utf-8' (Nur Express; betrifft nur Express-spezifische Methoden)
  8. res.contentType(type) (Nur Express)

Die Antwort muss im Kopf sein und wird zum Körper :

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

Die Reaktion kann in Kopf / Körper erfolgen und bleibt im Körper :

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

Die Antwort kann entweder in Kopf / Körper erfolgen und wird beendet :

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

Die Reaktion kann entweder in Kopf / Körper erfolgen und bleibt in ihrem aktuellen Zustand:

  1. res.addTrailers(headers)

Die Antwort muss im Kopf sein und wird beendet :

  1. return next([err]) (Nur Connect / Express)
  2. Alle Ausnahmen innerhalb der Middleware function(req, res, next)(nur Connect / Express)
  3. res.send(body|status[, headers|status[, status]]) (Nur Express)
  4. res.attachment(filename) (Nur Express)
  5. res.sendfile(path[, options[, callback]]) (Nur Express)
  6. res.json(obj[, headers|status[, status]]) (Nur Express)
  7. res.redirect(url[, status]) (Nur Express)
  8. res.cookie(name, val[, options]) (Nur Express)
  9. res.clearCookie(name[, options]) (Nur Express)
  10. res.render(view[, options[, fn]]) (Nur Express)
  11. res.partial(view[, options]) (Nur Express)
yonran
quelle
13
Ja, überprüfen Sie, ob Sie next () oder eine andere cb zweimal aufrufen.
Tony Gutierrez
3
Express-Links scheinen tot
Korhan Ozturk
25
Achten Sie auch auf diesen klassischen Fehler: res.redirect () stoppt die Ausführung von Anweisungen nicht ... kehren Sie also danach zurück. Andernfalls könnte anderer Code ausgeführt werden, der unbeabsichtigt den berühmten Header-Fehler verursachen könnte. Danke für die Erklärung!
KLoozen
Es ist normalerweise eine gute Idee, die Rückgabe am Ende Ihres Rückrufs zu verwenden, um dies zu vermeiden
thethakuri
4
Ich habe einen sehr kleinen Fehler in meiner Middleware gemacht, den ich returnvorher nicht gemacht habe next(), danke, das hat mich auf den Fehler hingewiesen!
illcrx
113

Ich bin auch eine Weile auf diesen Fehler gestoßen. Ich denke (hoffe), ich habe meinen Kopf darum gewickelt und wollte es hier als Referenz schreiben.

Wenn Sie Middleware hinzufügen, um mithilfe der Methode eine Verbindung herzustellen oder auszudrücken (die auf connect basiert), hängen app.useSie Elemente an Server.prototype.stackconnect an (zumindest mit der aktuellen npm install connect, die ab diesem Beitrag ganz anders aussieht als die eines Githubs). Wenn der Server eine Anforderung erhält, durchläuft er den Stapel und ruft die (request, response, next)Methode auf.

Das Problem ist, wenn in einem der Middleware-Elemente in den Antworttext oder die Header geschrieben wird (es sieht so aus, als ob es entweder / oder aus irgendeinem Grund ist), aber nicht aufgerufen wird response.end()und Sienext() dann aufrufen, wenn die Kernmethode Server.prototype.handleabgeschlossen ist, wird es bemerken Das:

  1. Es befinden sich keine weiteren Elemente im Stapel und / oder
  2. das response.headerSentist wahr

Es wird also ein Fehler ausgegeben. Der Fehler ist jedoch nur diese grundlegende Antwort (aus dem Connect- http.jsQuellcode:

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

Genau dort ist es ein Aufruf res.setHeader('Content-Type', 'text/plain');, den Sie wahrscheinlich in Ihrer renderMethode festgelegt haben, ohne response.end () aufzurufen , etwa:

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

Die Art und Weise, wie alles strukturiert werden muss, ist wie folgt:

Gute 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);

Problematische Middleware

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

Die problematische Middleware setzt den Antwortheader ohne Aufruf response.end()und Aufrufe next(), was den Server von connect verwirrt.

Lance Pollard
quelle
7
+1 Dies ist eine großartige Erklärung, aber was ist mit dem Fall, wenn Sie res.redirect () verwenden? Ich stoße häufig auf dieses Problem, wenn die Middleware versucht, basierend auf einer bestimmten Bedingung umzuleiten. Sollte die Middleware gemäß Ihrem Beispiel "Gute Middleware" nicht umleiten?
Qodeninja
Sie wissen, dass ich genau dieses Problem habe, weil Sie eine problematische Middleware nennen. Ich benötige jedoch einen Fall, in dem ich eine Antwort zurücksende, aber als Teil der Kette eine weitere Verarbeitung in einem separaten Controller durchführen möchte. Wie gehe ich vor, um diesen Fehler zu unterdrücken? ?
iQ.
57

Einige der Antworten in diesen Fragen und Antworten sind falsch. Die akzeptierte Antwort ist auch nicht sehr "praktisch", daher möchte ich eine Antwort veröffentlichen, die die Dinge in einfacheren Begriffen erklärt. Meine Antwort deckt 99% der Fehler ab, die ich immer wieder sehe. Die tatsächlichen Gründe für den Fehler finden Sie in der akzeptierten Antwort.


HTTP verwendet einen Zyklus, der eine Antwort pro Anforderung erfordert. Wenn der Client eine Anfrage sendet (z. B. POST oder GET), sollte der Server nur eine Antwort an ihn zurücksenden.

Diese Fehlermeldung:

Fehler: Header können nach dem Senden nicht festgelegt werden.

Dies geschieht normalerweise, wenn Sie mehrere Antworten für eine Anfrage senden. Stellen Sie sicher, dass die folgenden Funktionen nur einmal pro Anforderung aufgerufen werden:

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

(und einige weitere, die selten verwendet werden, überprüfen Sie die akzeptierte Antwort)

Der Routenrückruf wird nicht zurückgegeben, wenn diese Res-Funktionen aufgerufen werden. Es wird so lange ausgeführt, bis das Ende der Funktion oder eine return-Anweisung erreicht ist. Wenn Sie beim Senden einer Antwort zurückkehren möchten, können Sie dies folgendermaßen tun : return res.send().


Nehmen Sie zum Beispiel diesen 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' });
}

Wenn eine POST-Anforderung an / api / route1 gesendet wird, wird jede Zeile im Rückruf ausgeführt. A Header können nach dem Senden nicht festgelegt werden. Die Fehlermeldung wird ausgelöst, da res.json()sie zweimal aufgerufen wird. Dies bedeutet, dass zwei Antworten gesendet werden.

Pro Anfrage kann nur eine Antwort gesendet werden!


Der Fehler im obigen Codebeispiel war offensichtlich. Ein typischeres Problem ist, wenn Sie mehrere Zweige haben:

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.
    });
}

Diese Route mit angehängtem Rückruf findet eine Firma in einer Datenbank. Wenn wir eine Abfrage für ein Unternehmen durchführen, das nicht existiert, werden wir in die else ifFiliale gelangen und eine 404-Antwort senden. Danach fahren wir mit der nächsten Anweisung fort, die ebenfalls eine Antwort sendet. Jetzt haben wir zwei Antworten gesendet und die Fehlermeldung wird auftreten. Wir können diesen Code beheben, indem wir sicherstellen, dass wir nur eine Antwort senden:

.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);
  }
});

oder indem Sie zurückkehren, wenn die Antwort gesendet wird:

.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);
});

Ein großer Sünder sind asynchrone Funktionen. Nehmen Sie zum Beispiel die Funktion aus dieser Frage:

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.
  }
});

Hier haben wir eine asynchrone Funktion ( findOneAndUpdate()) im Codebeispiel. Wenn keine Fehler vorliegen, wird ( err) findOneAndUpdate()aufgerufen. Da diese Funktion asynchron ist, res.json(doc1)wird die sofort aufgerufen. Angenommen, es gibt keine Fehler in findOneAndUpdate(). Die res.json(doc2)im elseWillen werden dann aufgerufen. Es wurden nun zwei Antworten gesendet, und die Fehlermeldung " Header können nicht festgelegt werden" wird angezeigt .

In diesem Fall besteht die Lösung darin, das zu entfernen res.json(doc1). Um beide Dokumente an den Client zurückzusenden, könnte das res.json()in else als geschrieben werden res.json({ article: doc1, user: doc2 }).

Mika Sundland
quelle
2
Sie befinden sich in einer asynchronen Funktion und müssen return dieres.json
Genovo
Mein Problem war die Verwendung der res.sendfor-Schleife.
Maihan Nijat
1
Dies hat mir am Ende geholfen, das Problem zu verstehen und zu beheben. Vielen Dank :)
Pankaj Parkar
Vielen Dank, Sie sparen meine Zeit.
Mohammad Faisal
Dies ist definitiv die beste Antwort!
Juanma Menendez
53

Ich hatte das gleiche Problem und stellte fest, dass ich res.redirectohne returnAnweisung nextaufrief , sodass die Funktion auch unmittelbar danach aufgerufen wurde:

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

Welches hätte sein sollen:

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

Viele Leute haben diesen Fehler gemacht. Es ist verwirrend mit der asynchronen Verarbeitung. Höchstwahrscheinlich setzt ein Teil Ihres Codes Header im ersten Tick und dann führen Sie in einem zukünftigen Tick einen asynchronen Rückruf aus. Zwischendurch wird der Antwortheader gesendet, aber dann versuchen weitere Header (wie eine 30-fache Umleitung), zusätzliche Header hinzuzufügen. Es ist jedoch zu spät, da der Antwortheader bereits übertragen wurde.

Ich bin mir nicht sicher, was genau Ihren Fehler verursacht, aber ich betrachte Rückrufe als potenzielle Bereiche, die untersucht werden müssen.

Ein einfacher Tipp zur Vereinfachung Ihres Codes. Werde los app.configure()und rufe einfach app.usedirekt in deinem Top-Level-Bereich an.

Siehe auch das everyauth- Modul, das Facebook und etwa ein Dutzend anderer Authentifizierungsanbieter von Drittanbietern unterstützt.

Peter Lyons
quelle
Eine 30X-Umleitung ist ein HTTP-Antwortcode. w3.org/Protocols/rfc2616/rfc2616-sec10.html Die Codes 300-399 sind verschiedene Umleitungsvarianten, wobei 302 und 301 häufig verwendet werden, um den Client an eine alternative URL zu senden. Wenn Sie response.redirect (...) im Knoten ausführen, wird in der Antwort ein 30-facher Umleitungsheader gesendet.
Peter Lyons
3
Ohhhh. Ich stellte mir 30 Weiterleitungen hintereinander vor oder so
Janac Meena
17

Ich habe meinen Kopf über dieses Problem gekocht und es ist aufgrund eines unachtsamen Fehlers bei der Behandlung der Rückrufe passiert. Nicht zurückgegebene Rückrufe bewirken, dass die Antwort zweimal festgelegt wird.!

Mein Programm hatte einen Code, der die Anforderung validiert und die Datenbank abfragt. Nach der Überprüfung, ob ein Fehler vorliegt, habe ich die Datei index.js mit den Überprüfungsfehlern zurückgerufen. Und wenn die Validierung erfolgreich ist, wird die Datenbank mit Erfolg / Misserfolg erreicht.

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

Was geschah, ist: Wenn die Validierung fehlschlägt, wird der Rückruf aufgerufen und die Antwort festgelegt. Aber nicht zurückgekehrt. Also geht es weiter, die Methode geht zu db und trifft Erfolg / Misserfolg. Es ruft denselben Rückruf erneut auf, wodurch die Antwort jetzt zweimal festgelegt wird.

Die Lösung ist also einfach. Sie müssen den Rückruf zurückgeben, damit die Methode nicht weiter ausgeführt wird, sobald der Fehler aufgetreten ist, und daher das Antwortobjekt einmal festlegen

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);
Zufälligkeit
quelle
1
Vielen Dank! Dies stellte sich auch als mein Problem heraus. Habe gerade Strg + F gemacht und ein callback(...)ohne return;danach gefunden, was schließlich dazu führte res.send(...), dass es zweimal aufgerufen wurde.
15

Diese Art von Fehler wird angezeigt, wenn Sie nach dem Senden einer Antwort Anweisungen übergeben.

Zum Beispiel:

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

Dies führt zu dem Fehler, den Sie sehen, da nach dem Senden der Antwort Folgendes res.sendnicht ausgeführt wird.

Wenn Sie etwas tun möchten, sollten Sie dies tun, bevor Sie die Antwort senden.

Trojaner
quelle
Dies war mein genaues Problem :)
Joel Balmer
6

Manchmal kann dieser Fehler auftreten, wenn Sie versuchen, die Funktion next () nach res.end oder res.send aufzurufen . Versuchen Sie zu löschen, wenn Sie next () nach res.send oder res.end in Ihrer Funktion haben. Hinweis: Hier bedeutet next (), dass Sie nach der Antwort auf den Client mit Ihrer Antwort ( dh res.send oder res.end ) immer noch versuchen, Code auszuführen, um erneut zu antworten, sodass dies nicht legal ist.

Beispiel:

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

Entfernen Sie next()von oben Funktion und es wird funktionieren.

Surendra Parchuru
quelle
6

Wenn Sie Rückruffunktionen verwenden, verwenden Sie diese returnnach dem errBlock. Dies ist eines der Szenarien, in denen dieser Fehler auftreten kann.

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)
  })

Getestet auf Node-Version v10.16.0und Express4.16.4

Krishnadas PC
quelle
4

Dieser Fehler tritt auf, wenn Sie 2 Antworten senden. Beispielsweise :

if(condition A)
{ 

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

}

if (condition B){

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

Stellen Sie sich vor, wenn aus irgendeinem Grund Bedingung A und B wahr sind, erhalten Sie im zweiten renderMoment diesen Fehler

Badr Bellaj
quelle
3

In meinem Fall war es eine 304-Antwort (Caching), die das Problem verursachte.

Einfachste Lösung:

app.disable('etag');

Alternative Lösung hier, wenn Sie mehr Kontrolle wünschen:

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

mischte
quelle
In meinem Fall auch 304 Antwort. Ich benutze Fasern für die Verarbeitung. Wie auch immer, Ihre Antwort hilft sehr. Vielen Dank
Dileep Stanley
Kann jemand erklären, welche Auswirkungen das Entfernen des etag-Headers hat?
Mattwilsn
2
Mit ETags kann der Server keine Inhalte senden, die sich nicht geändert haben. Durch Deaktivieren wird diese Funktion deaktiviert. Der ETag-Wikipedia-Eintrag ( en.wikipedia.org/wiki/HTTP_ETag ) enthält eine ausführlichere Erklärung.
Blented
3

In meinem Fall geschah dies mit React und postal.js, als ich mich im componentWillUnmountRückruf meiner React-Komponente nicht von einem Kanal abmeldete .

Zoltán
quelle
2

Für jeden, der dazu kommt, und keine der anderen Lösungen hat geholfen. In meinem Fall manifestierte sich dies auf einer Route, die das Hochladen von Bildern handhabte, aber keine Zeitüberschreitungen behandelte . Wenn der Upload also zu lange dauerte und eine Zeitüberschreitung auftrat , als der Rückruf ausgelöst wurde Nachdem die Timeout-Antwort gesendet wurde , führte der Aufruf von res.send () zum Absturz, da die Header bereits so eingestellt waren, dass sie das Timeout berücksichtigen.

Dies konnte leicht reproduziert werden, indem eine sehr kurze Zeitüberschreitung eingestellt und die Route mit einem anständig großen Bild getroffen wurde. Der Absturz wurde jedes Mal reproduziert.

Mike
quelle
1
Wie haben Sie mit dem Timeout umgegangen, um dies zu vermeiden?
2

Ich habe mich nur gelehnt. Sie können die Antworten über diese Funktion übergeben:

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
quelle
2

Fügen Sie diese Mittelware hinzu und es wird funktionieren

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
quelle
2

Dies geschieht, wenn die Antwort an den Client gesendet wurde und Sie erneut versuchen, eine Antwort zu geben. Sie müssen in Ihrem Code einchecken, dass Sie irgendwo erneut eine Antwort an den Client zurückgeben, die diesen Fehler verursacht. Überprüfen Sie die Antwort und geben Sie sie einmal zurück, wenn Sie zurückkehren möchten.

Ankit Manchanda
quelle
1

Ich hatte dieses Problem, als ich Versprechen verschachtelte. Ein Versprechen innerhalb eines Versprechens würde 200 an den Server zurückgeben, aber dann würde die catch-Anweisung des äußeren Versprechens 500 zurückgeben. Sobald ich dies behoben hatte, verschwand das Problem.

rharding
quelle
Wie genau haben Sie das behoben? Ich habe das gleiche Problem mit Versprechungen. Ich kann es nicht vermeiden, sie zu verschachteln. Wie stoppe ich die Ausführung bei der return-Anweisung?
Saurabh
1

Kam von nuxt hierher , das Problem lag in der asyncDataMethode der Komponente , ich habe vergessen zu returnversprechen, welche Daten abruft und dort den Header setzt.

Nick Synev
quelle
1

Bitte überprüfen Sie, ob Ihr Code mehrere res.send () -Anweisungen für eine einzelne Anforderung zurückgibt. Wie als ich dieses Problem hatte ....

Ich war dieses Problem in meiner Restify Node-Anwendung. Der Fehler war das

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

Ich habe verschiedene Fälle mit einem Schalter bearbeitet, ohne eine Unterbrechung zu schreiben. Für diejenigen, die mit Switch Case wenig vertraut sind, wissen Sie, dass Sie ohne Unterbrechung Schlüsselwörter zurückgeben müssen. Der Code unter Groß- und Kleinschreibung und die nächsten Zeilen werden unabhängig davon ausgeführt. Obwohl ich eine einzelne res.send senden möchte, wurden aufgrund dieses Fehlers mehrere res.send-Anweisungen zurückgegeben, was dazu führte

Fehler kann keine Header setzen, nachdem sie an den Client gesendet wurden. Was durch Hinzufügen dieser oder Verwendung von return vor jeder res.send () -Methode wie return res.send (200) behoben wurde.

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

KNDheeraj
quelle
Vielen Dank für Ihre Inspiration, die mir auch passiert ist. Ich habe es auch mit sonst wenn Bedingung gelöst.
Amr AbdelRahman
1

Es ist sehr wahrscheinlich, dass dies eher eine Knotensache ist. In 99% der Fälle handelt es sich um einen doppelten Rückruf, der dazu führt, dass Sie zweimal antworten oder zweimal () zweimal usw.), verdammt sicher. Es löste mein Problem, next () in einer Schleife zu verwenden. Entfernen Sie das next () aus der Schleife oder beenden Sie den Aufruf mehrmals.

Naved Ahmad
quelle
1

Ich habe einen ähnlichen Fehler erhalten, als ich versucht habe, eine Antwort innerhalb einer Schleifenfunktion zu senden. Die einfache Lösung bestand darin, die zu bewegen

res.send ('Antwort senden');

außerhalb der Schleife, da Sie den Antwortheader nur einmal senden können.

https://www.tutorialspoint.com/nodejs/nodejs_response_object.htm

trustidkid
quelle
1

Ich füge einfach das Return-Schlüsselwort hinzu wie: return res.redirect("/great");und walla!

Emmanuel Benson
quelle
1

Ich hatte das gleiche Problem, das durch Mungo verursacht wurde.

Um Promisesdies zu beheben, müssen Sie Folgendes aktivieren , damit Sie Folgendes hinzufügen können: mongoose.Promise = global.Promisezu Ihrem Code, der die Verwendung ermöglicht native js promises.

Andere Alternativen zu dieser Lösung sind:

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

und

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

Sie müssen diese Pakete jedoch zuerst installieren.

Sina
quelle
1

Fehlersuche von selbst nach einem RND:

1) mein Fehlercode:

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

2) mein Erfolgscode

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

Der Unterschied ist, dass ich sendStatus () anstelle von status () verwendet habe .

nagender pratap chauhan
quelle
0

In Typescript bestand mein Problem darin, dass ich die Websocket-Verbindung nach dem Empfang einer Nachricht nicht geschlossen habe.

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

Wenn Sie keine Hilfe von oben erhalten: für Noobs Der Grund für diesen Fehler ist das mehrmalige Senden einer Anfrage. Lassen Sie uns in einigen Fällen Folgendes verstehen: - 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();   
        }

`Wenn Sie next () oben zweimal aufrufen, wird ein Fehler ausgelöst

  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);* }) })

Hier wird die Antwort zweimal gesendet. Überprüfen Sie, ob Sie bereits eine Antwort gesendet haben

Sanjay
quelle
0

In meinem Fall geschieht dies aufgrund mehrerer Rückrufe. Ich habe die next()Methode während des Codes mehrmals aufgerufen

Herr Ratnadeep
quelle
0

Mein Problem war, dass ich einen setIntervalLauf hatte, der einen if/elseBlock hatte, in dem sich die clearIntervalMethode befand in 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 {
            . . .

Putting the clearIntervalbefore the if/elsehat den Trick gemacht.

Mike K.
quelle
0

In meinem Fall, in einer Schleife, habe ich res.render()möglicherweise versucht, mehrmals aufzurufen.

Hasan Sefa Ozalp
quelle
-1

Im Falle dieses Fehlers musste ich nur res.end () tun.

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

Das andere Problem, mit dem Sie möglicherweise konfrontiert sind, ist der Code nach res.json und res. schreiben. In diesem Fall müssen Sie return verwenden, um die Ausführung danach zu stoppen.

 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 
};
Codierer
quelle