Kesalahan: Tidak dapat mengatur tajuk setelah dikirim ke klien

725

Saya cukup baru di Node.js dan saya mengalami beberapa masalah.

Saya menggunakan Node.js 4.10 dan Express 2.4.3.

Ketika saya mencoba mengakses http://127.0.0.1:8888/auth/facebook , saya akan dialihkan ke http://127.0.0.1:8888/auth/facebook_callback .

Saya kemudian menerima kesalahan berikut:

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)

Berikut ini adalah kode saya:

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

Bolehkah saya tahu apa yang salah dengan kode saya?

DjangoRocks
sumber
jawaban sederhana dari visionmedia: github.com/visionmedia/express/issues/634
shi11i
2
Google mengirim saya ke pertanyaan ini, tetapi versi ExpressJS yang lebih baru memiliki boolean res.headersSent yang dapat digunakan untuk memeriksa apakah aman untuk mengatur / mengirim tajuk
Julian Soro

Jawaban:

1113

The resobjek dalam Express adalah subclass dari Node.js inihttp.ServerResponse ( baca sumber http.js ). Anda diizinkan untuk menelepon res.setHeader(name, value)sesering yang Anda inginkan sampai Anda menelepon res.writeHead(statusCode). Setelah itu writeHead, tajuk dipanggang dan Anda hanya bisa menelepon res.write(data), dan akhirnya res.end(data).

Kesalahan "Kesalahan: Tidak dapat mengatur header setelah dikirim." berarti bahwa Anda sudah dalam status Tubuh atau Selesai, tetapi beberapa fungsi mencoba mengatur header atau statusCode. Ketika Anda melihat kesalahan ini, cobalah untuk mencari apa pun yang mencoba mengirim tajuk setelah beberapa badan telah ditulis. Misalnya, cari panggilan balik yang secara tidak sengaja dipanggil dua kali, atau kesalahan apa pun yang terjadi setelah tubuh dikirim.

Dalam kasus Anda, Anda menelepon res.redirect(), yang menyebabkan respons menjadi Selesai. Kemudian kode Anda melemparkan kesalahan ( res.reqadalah null). dan karena kesalahan terjadi dalam aktual Anda function(req, res, next)(bukan dalam panggilan balik), Connect dapat menangkapnya dan kemudian mencoba mengirim 500 halaman kesalahan. Tetapi karena header sudah dikirim, Node.js setHeadermelemparkan kesalahan yang Anda lihat.

Daftar lengkap Node.js / Metode respons ekspres dan kapan harus dipanggil:

Respons harus ada di Kepala dan tetap di Kepala :

  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]) (Hanya ekspres)
  7. res.charset = 'utf-8' (Hanya mengungkapkan; hanya memengaruhi metode khusus-Ekspres)
  8. res.contentType(type) (Hanya ekspres)

Respons harus ada di Kepala dan menjadi Tubuh :

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

Respons dapat di Kepala / Badan dan tetap di Tubuh :

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

Respons dapat di Kepala / Badan dan menjadi Selesai :

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

Respons dapat berada di salah satu Kepala / Badan dan tetap dalam kondisi saat ini:

  1. res.addTrailers(headers)

Respons harus ada di Kepala dan menjadi Selesai :

  1. return next([err]) (Sambungkan / Ekspresikan saja)
  2. Pengecualian dalam middleware function(req, res, next)(Hanya Hubungkan / Ekspres)
  3. res.send(body|status[, headers|status[, status]]) (Hanya ekspres)
  4. res.attachment(filename) (Hanya ekspres)
  5. res.sendfile(path[, options[, callback]]) (Hanya ekspres)
  6. res.json(obj[, headers|status[, status]]) (Hanya ekspres)
  7. res.redirect(url[, status]) (Hanya ekspres)
  8. res.cookie(name, val[, options]) (Hanya ekspres)
  9. res.clearCookie(name[, options]) (Hanya ekspres)
  10. res.render(view[, options[, fn]]) (Hanya ekspres)
  11. res.partial(view[, options]) (Hanya ekspres)
yonran
sumber
13
Yap, periksa untuk panggilan selanjutnya () atau cb lainnya dua kali.
Tony Gutierrez
3
Tautan ekspres tampaknya mati
Korhan Ozturk
25
juga hati-hati dengan kesalahan klasik ini: res.redirect () tidak menghentikan eksekusi pernyataan ... jadi kembalilah setelah itu. Kalau tidak, kode lain dapat dieksekusi yang secara tidak sengaja dapat menyebabkan kesalahan header yang terkenal. Terima kasih untuk penjelasannya!
KLoozen
Ini biasanya ide yang baik untuk menggunakan pengembalian di akhir panggilan balik Anda untuk menghindari ini
thethakuri
4
Saya membuat kesalahan yang sangat kecil di middleware saya, saya tidak pernah melakukannya returnsebelumnya next(), terima kasih ini menunjukkan kesalahan saya!
illcrx
113

Saya mengalami kesalahan ini juga untuk sementara waktu. Saya pikir (harapan) saya melingkari kepala saya, ingin menulisnya di sini untuk referensi.

Ketika Anda menambahkan middleware ke menghubungkan atau mengekspresikan (yang dibangun di atas koneksi) menggunakan app.usemetode ini, Anda menambahkan item ke Server.prototype.stackdalam terhubung (Setidaknya dengan saat ini npm install connect, yang terlihat sangat berbeda dari satu github pada posting ini). Ketika server mendapat permintaan, server akan beralih ke stack, memanggil (request, response, next)metode.

Masalahnya adalah, jika di salah satu item middleware menulis ke badan respons atau tajuk (sepertinya itu / atau karena alasan tertentu), tetapi tidak menelepon response.end()dan meneleponnext() saat Server.prototype.handlemetode inti selesai, ia akan melihat bahwa:

  1. tidak ada lagi item dalam tumpukan, dan / atau
  2. itu response.headerSentbenar.

Jadi, ada kesalahan. Tetapi kesalahan yang dilontarkannya hanyalah respons dasar ini (dari koneksihttp.js kode sumber :

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

Di sana, ia memanggil res.setHeader('Content-Type', 'text/plain');, yang kemungkinan besar telah Anda tetapkan dalam rendermetode Anda , tanpa memanggil response.end () , sesuatu seperti:

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

Cara semuanya perlu disusun adalah seperti ini:

Middleware yang bagus

// 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 yang Bermasalah

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

Middleware yang bermasalah mengatur header respons tanpa panggilan response.end()dan panggilan next(), yang membingungkan server connect.

Lance Pollard
sumber
7
+1 Ini adalah penjelasan yang bagus, tetapi bagaimana dengan kasus ketika Anda menggunakan res.redirect ()? Saya sering mengalami masalah ini ketika middleware mencoba mengalihkan berdasarkan beberapa kondisi. Haruskah middleware tidak mengalihkan, sesuai contoh "Good Middleware" Anda?
qodeninja
Anda tahu saya memiliki masalah yang tepat ini karena apa yang Anda sebut middleware bermasalah, namun saya memerlukan kasus di mana saya mengembalikan respons tetapi ingin melakukan pemrosesan lebih lanjut dalam pengontrol terpisah sebagai bagian dari rantai, bagaimana cara saya menekan kesalahan ini ?
iQ.
57

Beberapa jawaban dalam T&J ini salah. Jawaban yang diterima juga tidak terlalu "praktis", jadi saya ingin memposting jawaban yang menjelaskan hal-hal dalam istilah yang lebih sederhana. Jawaban saya akan mencakup 99% dari kesalahan yang saya lihat diposting berulang-ulang. Untuk alasan aktual di balik kesalahan, lihat jawaban yang diterima.


HTTP menggunakan siklus yang membutuhkan satu respons per permintaan. Ketika klien mengirim permintaan (misalnya POST atau GET) server hanya akan mengirim satu respons kembali ke sana.

Pesan kesalahan ini:

Kesalahan: Tidak dapat mengatur header setelah dikirim.

biasanya terjadi ketika Anda mengirim beberapa respons untuk satu permintaan. Pastikan fungsi-fungsi berikut dipanggil hanya sekali per permintaan:

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

(dan beberapa lagi yang jarang digunakan, periksa jawaban yang diterima)

Rute panggilan balik tidak akan kembali ketika fungsi res dipanggil. Ini akan terus berjalan sampai menyentuh akhir fungsi atau pernyataan kembali. Jika Anda ingin kembali saat mengirim tanggapan Anda dapat melakukannya seperti itu: return res.send().


Ambil contoh kode ini:

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

Ketika permintaan POST dikirim ke / api / route1, ia akan menjalankan setiap baris di callback. A Tidak dapat mengatur tajuk setelah dikirim pesan kesalahan akan dilemparkan karena res.json()dipanggil dua kali, artinya dua tanggapan dikirim.

Hanya satu respons yang dapat dikirim per permintaan!


Kesalahan dalam contoh kode di atas jelas. Masalah yang lebih khas adalah ketika Anda memiliki beberapa cabang:

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

Rute ini dengan panggilan balik terlampir menemukan perusahaan dalam database. Ketika melakukan kueri untuk perusahaan yang tidak ada, kami akan masuk ke dalam else ifcabang dan mengirim 404 tanggapan. Setelah itu, kami akan melanjutkan ke pernyataan berikutnya yang juga mengirimkan respons. Sekarang kami telah mengirim dua tanggapan dan pesan kesalahan akan muncul. Kami dapat memperbaiki kode ini dengan memastikan kami hanya mengirim satu respons:

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

atau dengan mengembalikan ketika respons dikirim:

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

Orang berdosa besar adalah fungsi yang tidak sinkron. Ambil fungsi dari pertanyaan ini , misalnya:

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

Di sini kita memiliki fungsi asinkron ( findOneAndUpdate()) dalam contoh kode. Jika tidak ada kesalahan ( err) findOneAndUpdate()akan dipanggil. Karena fungsi ini asinkron maka res.json(doc1)akan dipanggil segera. Asumsikan tidak ada kesalahan dalam findOneAndUpdate(). The res.json(doc2)di elsekemudian akan disebut. Dua tanggapan sekarang telah dikirim dan pesan kesalahan Tidak dapat mengatur tajuk terjadi.

Perbaikan, dalam hal ini, akan menghapus res.json(doc1). Untuk mengirim kedua dokumen kembali ke klien res.json()yang lain dapat ditulis sebagai res.json({ article: doc1, user: doc2 }).

Mika Sundland
sumber
2
Anda berada di dalam fungsi asynchronous, dan harus return yangres.json
Genovo
Masalah saya gunakan res.senddalam untuk loop.
Maihan Nijat
1
Ini membantu saya pada akhirnya untuk memahami dan memperbaiki masalah ini, Terima kasih banyak :)
Pankaj Parkar
terima kasih banyak kamu menghemat waktuku.
Mohammad Faisal
Ini jelas merupakan jawaban terbaik!
Juanma Menendez
53

Saya memiliki masalah yang sama dan menyadari bahwa itu karena saya menelepon res.redirecttanpa returnpernyataan, jadi nextfungsinya juga dipanggil segera setelah itu:

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

Yang seharusnya:

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

Banyak orang mengalami kesalahan ini. Ini membingungkan ini dengan pemrosesan async. Kemungkinan besar beberapa kode Anda mengatur tajuk di centang pertama dan kemudian Anda menjalankan panggilan balik async di centang di masa depan. Di antaranya, tajuk respons dikirim, tetapi tajuk lebih lanjut (seperti pengalihan 30X) mencoba menambahkan tajuk tambahan, tetapi sudah terlambat karena tajuk respons telah dikirim.

Saya tidak yakin persis apa yang menyebabkan kesalahan Anda, tetapi lihat semua panggilan balik sebagai area potensial untuk diselidiki.

Satu tip mudah untuk menyederhanakan kode Anda. Singkirkan app.configure()dan panggil sajaapp.use langsung di lingkup tingkat atas Anda.

Lihat juga modul everyauth , yang melakukan Facebook dan selusin penyedia otentikasi pihak ke-3 lainnya.

Peter Lyons
sumber
Pengalihan 30X adalah kode respons HTTP. w3.org/Protocols/rfc2616/rfc2616-sec10.html Kode 300-399 adalah variasi pengalihan yang berbeda, dengan 302 dan 301 yang biasa digunakan untuk mengirim klien ke URL alternatif. Saat Anda melakukan response.redirect (...) di node, header pengalihan 30X akan dikirim dalam respons.
Peter Lyons
3
Ohhhh. Saya membayangkan 30 pengalihan berturut-turut atau sesuatu
Janac Meena
17

Saya membungkukkan kepala karena masalah ini dan itu terjadi karena kesalahan ceroboh dalam menangani panggilan balik. panggilan balik yang tidak dikembalikan menyebabkan respons diatur dua kali.!

Program saya memiliki kode yang memvalidasi permintaan dan permintaan DB. setelah memvalidasi jika ada kesalahan, saya menelepon kembali index.js dengan kesalahan validasi. Dan jika validasi lolos, ia melanjutkan dan mencapai db dengan sukses / gagal.

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

Apa yang terjadi adalah: memetikan validasi gagal callback dipanggil dan respons diatur. Tetapi tidak dikembalikan. Jadi masih berlanjut metode menuju ke db dan tekan sukses / gagal. Ini memanggil panggilan balik yang sama lagi menyebabkan respons diatur dua kali sekarang.

Jadi solusinya sederhana, Anda perlu 'mengembalikan' callback sehingga metode tidak melanjutkan eksekusi, setelah kesalahan terjadi dan karenanya mengatur objek respons sekali

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);
keserampangan
sumber
1
Terima kasih! Ini ternyata juga masalah saya. Hanya melakukan ctrl + f dan menemukan callback(...)tanpa return;setelah itu yang akhirnya menyebabkan res.send(...)dipanggil dua kali.
15

Jenis kesalahan ini akan Anda dapatkan ketika Anda menyampaikan pernyataan setelah mengirim respons.

Sebagai contoh:

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

Akan menghasilkan kesalahan yang Anda lihat, karena begitu respons telah dikirim, berikut ini res.send tidak akan dieksekusi.

Jika Anda ingin melakukan sesuatu, Anda harus melakukannya sebelum mengirim respons.

Trojan
sumber
Ini adalah masalah persis saya :)
Joel Balmer
6

Kadang-kadang Anda mungkin mendapatkan kesalahan ini ketika Anda mencoba memanggil fungsi next () setelah res.end atau res.send , cobalah untuk menghapus jika Anda memiliki fungsi next () setelah res.send atau res.end dalam fungsi Anda. Catatan: di sini next () berarti setelah menanggapi klien dengan respons Anda ( mis. Kirim ulang atau kirim ulang ), Anda masih mencoba menjalankan beberapa kode untuk merespons lagi sehingga tidak sah.

Contoh:

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

hapus next()dari fungsi di atas dan itu akan berfungsi.

Surendra Parchuru
sumber
6

Jika Anda menggunakan fungsi panggilan balik, gunakan returnsetelah errpemblokiran. Ini adalah salah satu skenario di mana kesalahan ini dapat terjadi.

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

Diuji pada versi Node v10.16.0dan ekspres4.16.4

Krishnadas PC
sumber
4

Kesalahan ini terjadi ketika Anda mengirim 2 tanggapan. Sebagai contoh :

if(condition A)
{ 

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

}

if (condition B){

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

Bayangkan jika karena suatu alasan kondisi A dan B benar sehingga pada detik renderAnda akan mendapatkan kesalahan itu

Badr Bellaj
sumber
3

Dalam kasus saya itu adalah respons 304 (caching) yang menyebabkan masalah.

Solusi termudah:

app.disable('etag');

Solusi alternatif di sini jika Anda ingin lebih banyak kontrol:

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

berbaur
sumber
Dalam kasus saya juga 304 tanggapan. Saya menggunakan Serat untuk diproses. Bagaimanapun jawaban Anda sangat membantu. terima kasih
stanley Dileep
Adakah yang bisa menjelaskan implikasinya untuk menghapus header etag?
mattwilsn
2
ETag memungkinkan server untuk tidak mengirim konten yang tidak berubah. Mematikan fitur ini menonaktifkan fitur ini. Entri wikipedia ETag ( en.wikipedia.org/wiki/HTTP_ETag ) memiliki penjelasan yang lebih panjang.
Dicampur
3

Dalam kasus saya ini terjadi dengan React dan postal.js ketika saya tidak berhenti berlangganan dari saluran dalam componentWillUnmountpanggilan balik dari komponen React saya.

Zoltán
sumber
2

Bagi siapa pun yang datang ke ini dan tidak ada solusi lain yang membantu, dalam kasus saya ini bermanifestasi pada rute yang menangani pengunggahan gambar tetapi tidak menangani batas waktu , dan dengan demikian jika pengunggahan terlalu lama dan kehabisan waktu, ketika panggilan balik dipecat setelah batas waktu respon telah dikirim , memanggil res.send () mengakibatkan crash karena tajuk sudah ditetapkan untuk memperhitungkan batas waktu.

Ini mudah direproduksi dengan menetapkan batas waktu yang sangat singkat dan mengenai rute dengan gambar yang cukup besar, kecelakaan itu direproduksi setiap waktu.

Mike
sumber
1
bagaimana Anda menangani batas waktu untuk menghindari ini?
2

Hanya bersandar ini. Anda dapat meneruskan respons melalui fungsi ini:

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

Tambahkan middlware ini dan itu akan berhasil

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

Ini terjadi ketika respons dikirim ke klien dan lagi-lagi Anda mencoba memberikan respons. Anda harus memeriksa kode Anda bahwa di suatu tempat Anda mengembalikan respons ke klien lagi yang menyebabkan kesalahan ini. Periksa dan kembalikan respons sekali ketika Anda ingin kembali.

Ankit Manchanda
sumber
1

Saya memiliki masalah ini ketika saya bersarang janji. Sebuah janji di dalam janji akan mengembalikan 200 ke server, tetapi kemudian pernyataan tangkapan janji luar akan mengembalikan 500. Setelah saya memperbaiki ini, masalahnya hilang.

rharding
sumber
bagaimana tepatnya Anda memperbaikinya? Saya memiliki masalah yang sama dengan janji-janji. Saya tidak bisa menghindari membuat sarang mereka ... jadi bagaimana cara saya menghentikan eksekusi pada pernyataan pengembalian?
saurabh
1

Datang ke sini dari nuxt , masalahnya adalah pada metode komponen asyncData, saya lupa returnberjanji yang mengambil data dan mengatur tajuk di sana.

Nick Synev
sumber
1

Periksa apakah kode Anda mengembalikan beberapa pernyataan res.send () untuk satu permintaan. Seperti ketika saya memiliki masalah ini ....

Saya adalah masalah ini dalam aplikasi node restify saya. Kesalahannya adalah itu

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

Saya menangani berbagai kasus menggunakan sakelar tanpa jeda tulisan. Bagi mereka yang terbiasa dengan sakelar tahu bahwa tanpa putus, kembalikan kata kunci. Kode dalam huruf besar dan baris berikutnya akan dieksekusi tidak peduli apa. Jadi, meskipun saya ingin mengirim res.send tunggal, karena kesalahan ini ia mengembalikan beberapa res.send laporan, yang diminta

kesalahan tidak dapat mengatur tajuk setelah dikirim ke klien. Yang dapat diselesaikan dengan menambahkan ini atau menggunakan return sebelum setiap metode res.send () seperti return res.send (200)

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

KNDheeraj
sumber
terima kasih atas ilhammu sama yang terjadi padaku. Saya menyelesaikannya juga dengan kondisi lain jika.
Amr AbdelRahman
1

Sangat mungkin bahwa ini lebih merupakan hal simpul, 99% dari waktu itu merupakan panggilan balik ganda yang menyebabkan Anda merespons dua kali, atau berikutnya () dua kali dll, sangat yakin. Ini memecahkan masalah saya menggunakan next () di dalam satu lingkaran. Hapus next () dari loop atau berhenti memanggilnya lebih dari satu kali.

Naved Ahmad
sumber
1

Saya cukup menambahkan kata kunci kembali seperti: return res.redirect("/great");dan walla!

Emmanuel Benson
sumber
1

Saya memiliki masalah yang sama yang disebabkan oleh luwak.

untuk memperbaikinya Anda harus mengaktifkan Promises, sehingga Anda dapat menambahkan: mongoose.Promise = global.Promiseke kode Anda, yang memungkinkan penggunaan native js promises.

alternatif lain untuk soloution ini adalah:

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

dan

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

tetapi Anda harus menginstal paket ini terlebih dahulu.

sina
sumber
1

kesalahan menemukan dengan sendirinya setelah RND:

1) kode kesalahan saya:

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

2) kode kesuksesan saya

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

perbedaannya adalah saya menggunakan sendStatus () alih-alih status () .

nagender pratap chauhan
sumber
0

Dalam naskah, masalah saya adalah saya tidak menutup koneksi websocket setelah menerima pesan.

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

Jika Anda tidak mendapatkan bantuan dari atas: untuk noobs Alasan di balik kesalahan ini adalah mengirim permintaan beberapa kali, biarkan kami memahami dari beberapa kasus: - 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();   
        }

`dalam panggilan di atas berikutnya () dua kali akan memunculkan kesalahan

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

di sini respons dikirim dua kali periksa apakah Anda sudah mengirim respons

Sanjay
sumber
0

Dalam kasus saya ini terjadi karena beberapa panggilan balik. Saya telah memanggil next()metode berkali-kali selama kode

Pak Ratnadeep
sumber
0

Masalah saya adalah saya setIntervalmenjalankan, yang memiliki if/elseblok, di mana clearIntervalmetodenya berada di dalam 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 {
            . . .

Menempatkan clearIntervalsebelum if/elsemelakukan trik.

Mike K.
sumber
0

Dalam kasus saya, Dalam satu lingkaran, saya res.render()mungkin telah mencoba menelepon beberapa kali.

Hasan Sefa Ozalp
sumber
-1

Yang harus saya lakukan jika kesalahan ini adalah res.end ().

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

Masalah lain yang mungkin Anda hadapi adalah ada kode setelah res.json dan res. menulis. Dalam hal ini, Anda harus menggunakan kembali untuk menghentikan eksekusi setelah itu.

 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 
};
pembuat kode
sumber