Lỗi: Không thể đặt tiêu đề sau khi chúng được gửi đến máy khách


724

Tôi khá mới với Node.js và tôi đang gặp một số vấn đề.

Tôi đang sử dụng Node.js 4.10 và Express 2.4.3.

Khi tôi cố gắng truy cập http://127.0.0.1:8888/auth/facebook , tôi sẽ được chuyển hướng đến http://127.0.0.1:8888/auth/facebook_callback .

Sau đó tôi đã nhận được lỗi sau:

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)

Sau đây là mã của tôi:

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

Tôi có thể biết những gì sai với mã của tôi?


câu trả lời đơn giản từ Visionmedia: github.com/visionmedia/express/issues/634
shi11i

2
Google đã gửi cho tôi câu hỏi này, nhưng các phiên bản mới hơn của ExpressJS có res.headersSent boolean có thể được sử dụng để kiểm tra xem có an toàn để đặt / gửi tiêu đề không
Julian Soro

Câu trả lời:


1112

Đối restượng trong Express là một lớp con của Node.jshttp.ServerResponse ( đọc nguồn http.js ). Bạn được phép gọi res.setHeader(name, value)thường xuyên như bạn muốn cho đến khi bạn gọi res.writeHead(statusCode). Sau đó writeHead, các tiêu đề được nướng vào và bạn chỉ có thể gọi res.write(data), và cuối cùngres.end(data) .

Lỗi "Lỗi: Không thể đặt tiêu đề sau khi chúng được gửi." có nghĩa là bạn đã ở trạng thái Thân hoặc Hoàn thành, nhưng một số chức năng đã cố gắng đặt tiêu đề hoặc mã trạng thái. Khi bạn thấy lỗi này, hãy cố gắng tìm kiếm bất cứ điều gì cố gắng gửi tiêu đề sau khi một số phần thân đã được viết. Ví dụ: tìm kiếm các cuộc gọi lại vô tình được gọi hai lần hoặc bất kỳ lỗi nào xảy ra sau khi cơ thể được gửi.

Trong trường hợp của bạn, bạn đã gọi res.redirect(), điều này khiến cho phản hồi trở thành Kết thúc. Sau đó, mã của bạn đã ném một lỗi ( res.reqnull). và do lỗi xảy ra trong thực tế của bạn function(req, res, next)(không phải trong một cuộc gọi lại), Connect đã có thể bắt lỗi và sau đó cố gắng gửi một trang lỗi 500. Nhưng vì các tiêu đề đã được gửi, Node.js setHeaderđã ném lỗi mà bạn thấy.

Danh sách đầy đủ các phương thức phản hồi Node.js / Express và khi nào chúng phải được gọi:

Phản hồi phải ở trong Head và vẫn ở Head :

  1. res.writeContinue()
  2. res.statusCode = 404
  3. res.setHeader(name, value)
  4. res.getHeader(name)
  5. res.removeHeader(name)
  6. res.header(key[, val]) (Chỉ thể hiện)
  7. res.charset = 'utf-8' (Chỉ Express; chỉ ảnh hưởng đến các phương thức Express cụ thể)
  8. res.contentType(type) (Chỉ thể hiện)

Phản ứng phải ở trong Đầu và trở thành Thân thể :

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

Phản ứng có thể ở cả Đầu / Cơ thể và vẫn ở trong Cơ thể :

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

Phản hồi có thể ở cả Đầu / Cơ thể và kết thúc :

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

Phản hồi có thể ở cả Head / Body và vẫn ở trạng thái hiện tại:

  1. res.addTrailers(headers)

Phản hồi phải ở trong Head và trở thành Kết thúc :

  1. return next([err]) (Chỉ kết nối / Express)
  2. Bất kỳ trường hợp ngoại lệ nào trong phần mềm trung gian function(req, res, next)(chỉ kết nối / Express)
  3. res.send(body|status[, headers|status[, status]]) (Chỉ thể hiện)
  4. res.attachment(filename) (Chỉ thể hiện)
  5. res.sendfile(path[, options[, callback]]) (Chỉ thể hiện)
  6. res.json(obj[, headers|status[, status]]) (Chỉ thể hiện)
  7. res.redirect(url[, status]) (Chỉ thể hiện)
  8. res.cookie(name, val[, options]) (Chỉ thể hiện)
  9. res.clearCookie(name[, options]) (Chỉ thể hiện)
  10. res.render(view[, options[, fn]]) (Chỉ thể hiện)
  11. res.partial(view[, options]) (Chỉ thể hiện)

13
Đúng, kiểm tra để gọi next () hoặc cb khác hai lần.
Tony Gutierrez

3
Liên kết nhanh dường như đã chết
Korhan Ozturk

25
cũng coi chừng sai lầm kinh điển này: res.redirect () không dừng thực thi câu lệnh ... vì vậy hãy quay lại sau nó. Mặt khác, mã khác có thể được thực thi có thể gây ra lỗi tiêu đề nổi tiếng. Thanx cho lời giải thích!
KLoozen

Thông thường nên sử dụng trả lại vào cuối cuộc gọi lại của bạn để tránh điều này
thethakuri

4
Tôi đã mắc một lỗi rất nhỏ trong phần mềm trung gian của mình, tôi đã không làm điều returnđó trước đây next(), nhờ điều này đã chỉ cho tôi lỗi!
illcrx

113

Tôi đã gặp phải lỗi này trong một thời gian. Tôi nghĩ (hy vọng) tôi đã quấn đầu xung quanh nó, muốn viết nó ở đây để tham khảo.

Khi bạn thêm phần mềm trung gian để kết nối hoặc thể hiện (được xây dựng trên kết nối) bằng app.usephương thức, bạn sẽ nối thêm các mục Server.prototype.stackvào kết nối (Ít nhất là với hiện tại npm install connect, trông khá khác so với một github như của bài đăng này). Khi máy chủ nhận được yêu cầu, nó lặp lại trên ngăn xếp, gọi (request, response, next)phương thức.

Vấn đề là, nếu trong một trong các mục phần mềm trung gian ghi vào phần thân hoặc tiêu đề phản hồi (có vẻ như đó là / hoặc vì một lý do nào đó), nhưng không gọi response.end()và bạn gọinext() sau đó khi Server.prototype.handlephương thức cốt lõi hoàn thành, nó sẽ chú ý cái đó:

  1. không có thêm mục nào trong ngăn xếp và / hoặc
  2. đó response.headerSentlà sự thật

Vì vậy, nó ném một lỗi. Nhưng lỗi nó ném chỉ là phản hồi cơ bản này (từ http.jsmã nguồn kết nối :

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

Ngay tại đó, nó đang gọi res.setHeader('Content-Type', 'text/plain');, mà bạn có khả năng đã đặt trongrender phương thức , mà không gọi answer.end () , đại loại như:

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

Cách mọi thứ cần được cấu trúc là như thế này:

Đồ dùng tốt

// 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 có vấn đề

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

Phần mềm trung gian có vấn đề đặt tiêu đề phản hồi mà không gọi response.end()và gọi next(), điều này gây nhầm lẫn cho máy chủ của kết nối.


7
+1 Đây là một lời giải thích tuyệt vời, nhưng còn trường hợp khi bạn sử dụng res.redirect () thì sao? Tôi thường xuyên gặp phải vấn đề này khi phần mềm trung gian đang cố gắng chuyển hướng dựa trên một số điều kiện. Phần mềm trung gian không nên chuyển hướng, theo ví dụ "Good Middleware" của bạn?
qodeninja

Bạn biết tôi có vấn đề chính xác này do những gì bạn gọi là phần mềm trung gian có vấn đề, tuy nhiên tôi cần một trường hợp tôi trả lời phản hồi nhưng muốn xử lý thêm trong một bộ điều khiển riêng như một phần của chuỗi, làm cách nào để khắc phục lỗi này ?
iQ.

57

Một số câu trả lời trong câu hỏi và trả lời này là sai. Câu trả lời được chấp nhận cũng không "thực tế" lắm, vì vậy tôi muốn đăng một câu trả lời giải thích mọi thứ bằng những thuật ngữ đơn giản hơn. Câu trả lời của tôi sẽ bao gồm 99% các lỗi tôi thấy được đăng đi đăng lại nhiều lần. Đối với các lý do thực tế đằng sau lỗi, hãy xem câu trả lời được chấp nhận.


HTTP sử dụng một chu trình yêu cầu một phản hồi cho mỗi yêu cầu. Khi máy khách gửi yêu cầu (ví dụ POST hoặc GET), máy chủ chỉ nên gửi một phản hồi lại cho nó.

Thông báo lỗi này:

Lỗi: Không thể đặt tiêu đề sau khi chúng được gửi.

thường xảy ra khi bạn gửi một số phản hồi cho một yêu cầu. Đảm bảo rằng các chức năng sau chỉ được gọi một lần cho mỗi yêu cầu:

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

(và một vài điều nữa hiếm khi được sử dụng, kiểm tra câu trả lời được chấp nhận)

Cuộc gọi lại tuyến đường sẽ không trở lại khi các chức năng res này được gọi. Nó sẽ tiếp tục chạy cho đến khi nó kết thúc hàm hoặc một câu lệnh return. Nếu bạn muốn quay lại khi gửi phản hồi, bạn có thể làm như vậy : return res.send().


Lấy ví dụ mã này:

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

Khi một yêu cầu POST được gửi đến / api / route1, nó sẽ chạy mọi dòng trong cuộc gọi lại. Một Can không đặt tiêu đề sau khi chúng được gửi thông báo lỗi sẽ được ném vì res.json()được gọi là hai lần, có nghĩa là hai câu trả lời được gửi đi.

Chỉ có thể gửi một phản hồi cho mỗi yêu cầu!


Các lỗi trong mẫu mã ở trên là rõ ràng. Một vấn đề điển hình hơn là khi bạn có một vài chi nhánh:

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

Tuyến đường này với cuộc gọi lại đính kèm tìm thấy một công ty trong cơ sở dữ liệu. Khi thực hiện truy vấn cho một công ty không tồn tại, chúng tôi sẽ vào bên trong else ifchi nhánh và gửi phản hồi 404. Sau đó, chúng tôi sẽ tiếp tục tuyên bố tiếp theo cũng sẽ gửi phản hồi. Bây giờ chúng tôi đã gửi hai phản hồi và thông báo lỗi sẽ xảy ra. Chúng tôi có thể sửa mã này bằng cách đảm bảo chúng tôi chỉ gửi một phản hồi:

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

hoặc bằng cách quay lại khi phản hồi được gửi:

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

Một tội nhân lớn là các chức năng không đồng bộ. Lấy chức năng từ câu hỏi này , ví dụ:

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

Ở đây chúng ta có một hàm không đồng bộ ( findOneAndUpdate()) trong mẫu mã. Nếu không có lỗi ( err) findOneAndUpdate()sẽ được gọi. Bởi vì chức năng này không đồng bộ nên res.json(doc1)sẽ được gọi ngay lập tức. Giả sử không có lỗi trong findOneAndUpdate(). Các res.json(doc2)di elsechúc sau đó sẽ được gọi. Hai phản hồi đã được gửi và thông báo lỗi không thể đặt tiêu đề xảy ra.

Sửa chữa, trong trường hợp này, sẽ là để loại bỏ res.json(doc1). Để gửi cả hai tài liệu trở lại máy khách, res.json()cái khác có thể được viết là res.json({ article: doc1, user: doc2 }).


2
Bạn đang ở trong một chức năng không đồng bộ, và phải return sựres.json
Genovo

Vấn đề của tôi là sử dụng res.sendtrong vòng lặp.
Maihan Nijat

1
Điều này đã giúp tôi cuối cùng để hiểu và khắc phục vấn đề, Cảm ơn rất nhiều :)
Pankaj Parkar

cảm ơn bạn rất nhiều bạn tiết kiệm thời gian của tôi
Mohammad Faisal

Đây chắc chắn là câu trả lời tốt nhất!
Juanma Menendez

53

Tôi gặp vấn đề tương tự và nhận ra rằng đó là vì tôi đã gọi res.redirectmà không có returncâu lệnh, nên nexthàm này cũng được gọi ngay sau đó:

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

Mà nên có:

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

43

Rất nhiều người gặp lỗi này. Đó là một điều khó hiểu với việc xử lý không đồng bộ. Rất có thể một số mã của bạn đang đặt tiêu đề trong tích tắc đầu tiên và sau đó bạn đang chạy một cuộc gọi lại không đồng bộ trong một đánh dấu trong tương lai. Ở giữa, tiêu đề phản hồi được gửi, nhưng sau đó các tiêu đề tiếp theo (như chuyển hướng 30X) cố gắng thêm các tiêu đề bổ sung, nhưng đã quá muộn vì tiêu đề phản hồi đã được truyền đi.

Tôi không chắc chính xác điều gì gây ra lỗi của bạn, nhưng hãy xem bất kỳ cuộc gọi lại nào là khu vực tiềm năng để điều tra.

Một mẹo dễ dàng để đơn giản hóa mã của bạn. Loại bỏ app.configure()và chỉ cần gọi app.usetrực tiếp trong phạm vi cấp cao nhất của bạn.

Xem thêm mô-đun everyauth , Facebook và một tá nhà cung cấp xác thực bên thứ 3 khác.


Chuyển hướng 30X là mã phản hồi HTTP. w3.org/Prot Protocol / rfc2616 / rfc2616-sec10.html Mã 300-399 là các biến thể khác nhau của chuyển hướng, với 302 và 301 thường được sử dụng để gửi ứng dụng khách đến một URL thay thế. Khi bạn thực hiện answer.redirect (...) trong nút, tiêu đề chuyển hướng 30X sẽ được gửi trong phản hồi.
Peter Lyons

3
Ồ Tôi đã tưởng tượng 30 chuyển hướng liên tiếp hoặc một cái gì đó
Janac Meena 16/03/18

17

Tôi đã luộc đầu về vấn đề này và nó đã xảy ra do một lỗi bất cẩn trong việc xử lý các cuộc gọi lại. cuộc gọi lại không trả về khiến phản hồi được đặt hai lần.!

Chương trình của tôi có một mã xác nhận yêu cầu và truy vấn DB. sau khi xác thực nếu có lỗi, tôi đã gọi lại index.js với các lỗi xác thực. Và nếu xác thực vượt qua, nó sẽ tiếp tục và đạt được thành công / thất bại.

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

Điều gì đã xảy ra là: Xác thực Incase thất bại trong cuộc gọi lại được gọi và phản hồi được thiết lập. Nhưng không được trả lại. Vì vậy, nó vẫn tiếp tục phương thức đi đến db và đạt thành công / thất bại. Nó gọi lại cùng một cuộc gọi lại khiến cho phản hồi được đặt hai lần bây giờ.

Vì vậy, giải pháp rất đơn giản, bạn cần 'trả về' cuộc gọi lại để phương thức không tiếp tục thực thi, một khi lỗi đã xảy ra và do đó đặt đối tượng phản hồi một lần

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

1
Cảm ơn! Điều này hóa ra cũng là vấn đề của tôi. Chỉ cần thực hiện một ctrl + f và tìm thấy một cái callback(...)mà không có return;sau nó cuối cùng đã res.send(...)được gọi là hai lần.

15

Loại lỗi này bạn sẽ nhận được khi bạn chuyển các câu lệnh sau khi gửi phản hồi.

Ví dụ:

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

Sẽ dẫn đến lỗi bạn đang thấy, bởi vì một khi phản hồi đã được gửi, những điều sau đây res.sendsẽ không được thực thi.

Nếu bạn muốn làm bất cứ điều gì, bạn nên làm điều đó trước khi gửi phản hồi.


Đây là vấn đề chính xác của tôi :)
Joel Balmer

6

Đôi khi bạn có thể gặp lỗi này khi bạn cố gắng gọi hàm next () sau res.end hoặc res.send , cố gắng xóa nếu bạn có next () sau res.send hoặc res.end trong hàm của bạn. Lưu ý: ở đây next () có nghĩa là sau khi trả lời khách hàng bằng phản hồi của bạn ( tức là res.send hoặc res.end ), bạn vẫn đang cố thực thi một số mã để phản hồi lại vì vậy nó không hợp pháp.

Thí dụ :

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

loại bỏ next()khỏi chức năng trên và nó sẽ hoạt động.


6

Nếu bạn đang sử dụng chức năng gọi lại, hãy sử dụng returnsau errkhối. Đây là một trong những tình huống có thể xảy ra lỗi này.

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

Đã thử nghiệm trên phiên bản Node v10.16.0và express4.16.4


4

Lỗi này xảy ra khi bạn gửi 2 phản hồi. Ví dụ :

if(condition A)
{ 

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

}

if (condition B){

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

Hãy tưởng tượng nếu vì lý do nào đó điều kiện A và B là đúng thì trong giây thứ hai renderbạn sẽ gặp lỗi đó


3

Trong trường hợp của tôi, đó là phản hồi 304 (bộ nhớ đệm) gây ra sự cố.

Giải pháp dễ nhất:

app.disable('etag');

Giải pháp thay thế ở đây nếu bạn muốn kiểm soát nhiều hơn:

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


Trong trường hợp của tôi cũng đáp ứng 304. Tôi đang sử dụng sợi để xử lý. Bất kỳ cách nào câu trả lời của bạn giúp rất nhiều. cảm ơn bạn
Dileep stanley

Bất cứ ai có thể giải thích những tác động của việc loại bỏ tiêu đề etag?
mattwilsn

2
ETags cho phép máy chủ không gửi nội dung chưa thay đổi. Tắt nó sẽ vô hiệu hóa tính năng này. Mục wikipedia của ETag ( en.wikipedia.org/wiki/HTTP_ETag ) có phần giải thích dài hơn.
thổi vào

3

Trong trường hợp của tôi, điều này đã xảy ra với React và Postal.js khi tôi không hủy đăng ký kênh trong phần componentWillUnmountgọi lại của thành phần React của mình.


2

Đối với bất kỳ ai đến với điều này và không có giải pháp nào khác giúp được, trong trường hợp của tôi, biểu hiện này trên tuyến xử lý tải lên hình ảnh nhưng không xử lý thời gian chờ , và do đó, nếu quá trình tải lên mất quá nhiều thời gian, khi cuộc gọi lại bị hủy sau khi phản hồi hết thời gian đã được gửi , việc gọi res.send () dẫn đến sự cố do các tiêu đề đã được đặt thành tài khoản cho thời gian chờ.

Điều này được tái tạo dễ dàng bằng cách đặt thời gian chờ rất ngắn và nhấn tuyến đường với hình ảnh lớn, sự cố được tái tạo mỗi lần.


1
Làm thế nào bạn xử lý thời gian chờ để tránh điều này?

2

Chỉ cần nghiêng này. Bạn có thể chuyển các câu trả lời thông qua chức năng này:

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

2

Thêm phần mềm trung gian này và nó sẽ hoạt động

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

2

Điều này xảy ra khi phản hồi được gửi đến khách hàng và một lần nữa bạn đang cố gắng đưa ra phản hồi. Bạn phải kiểm tra lại mã của mình rằng một nơi nào đó bạn đang trả lại phản hồi cho khách hàng gây ra lỗi này. Kiểm tra và trả lời phản hồi một lần khi bạn muốn quay lại.


1

Tôi đã có vấn đề này khi tôi đang làm tổ những lời hứa. Một lời hứa bên trong lời hứa sẽ trả lại 200 cho máy chủ, nhưng sau đó, tuyên bố bắt của lời hứa bên ngoài sẽ trả lại 500. Một khi tôi sửa lỗi này, vấn đề sẽ biến mất.


Làm thế nào chính xác bạn đã sửa lỗi này? Tôi có cùng một vấn đề với những lời hứa. Tôi không thể tránh lồng chúng ... vậy làm thế nào để tôi dừng thực thi tại câu lệnh return?
saurabh

1

Đến đây từ nuxt , vấn đề là ở asyncDataphương thức của thành phần , tôi đã quên returnhứa sẽ lấy dữ liệu và đặt tiêu đề ở đó.


1

Vui lòng kiểm tra xem mã của bạn có trả về nhiều câu lệnh res.send () cho một yêu cầu không. Giống như khi tôi gặp vấn đề này ....

Tôi đã gặp vấn đề này trong ứng dụng nút restify của tôi. Sai lầm là

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

Tôi đã xử lý các trường hợp khác nhau bằng cách sử dụng chuyển đổi mà không viết phá vỡ. Đối với những người ít quen thuộc với trường hợp chuyển đổi biết rằng không nghỉ, trả lại từ khóa. Mã theo trường hợp và các dòng tiếp theo của nó sẽ được thực thi bất kể điều gì. Vì vậy, mặc dù tôi muốn gửi res.send duy nhất, do lỗi này, nó đã trả lại nhiều câu lệnh res.send, điều đó đã nhắc

lỗi không thể đặt tiêu đề sau khi chúng được gửi đến máy khách. Điều này đã được giải quyết bằng cách thêm điều này hoặc sử dụng return trước mỗi phương thức res.send () như return res.send (200)

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


cảm ơn bạn đã truyền cảm hứng cho tôi Tôi đã giải quyết nó với người khác nếu có điều kiện.
Amr AbdelRahman

1

Rất có khả năng đây là một điều của nút, 99% thời gian đó là một cuộc gọi lại kép khiến bạn phải trả lời hai lần hoặc tiếp theo () ing hai lần, v.v. Nó đã giải quyết vấn đề của tôi là sử dụng next () bên trong một vòng lặp. Xóa tiếp theo () khỏi vòng lặp hoặc ngừng gọi nó nhiều hơn một lần.



1

Tôi chỉ cần thêm từ khóa trở lại như: return res.redirect("/great");và walla!


1

Tôi có cùng một vấn đề gây ra bởi cầy mangut.

để sửa lỗi mà bạn phải kích hoạt Promises, để bạn có thể thêm: mongoose.Promise = global.Promisevào mã của mình, cho phép sử dụngnative js promises .

các lựa chọn thay thế khác cho giải pháp này là:

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

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

nhưng bạn cần cài đặt các gói này trước.


1

tự tìm lỗi sau một RND:

1) mã lỗi của tôi:

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

2) mã thành công của tôi

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

sự khác biệt là tôi đã sử dụng sendStatus () thay vì status () .


0

Trong Bản in, vấn đề của tôi là tôi đã không đóng kết nối websocket sau khi nhận được tin nhắn.

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

0

Nếu bạn không nhận được sự giúp đỡ từ phía trên: vì noobs Lý do đằng sau lỗi này là gửi yêu cầu nhiều lần, hãy cho chúng tôi hiểu từ một số trường hợp: - 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();   
        }

`trong lần gọi tiếp theo () hai lần sẽ phát sinh lỗi

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

ở đây trả lời là gửi hai lần kiểm tra xem bạn đã gửi phản hồi chưa


0

Trong trường hợp của tôi, nó xảy ra do nhiều cuộc gọi lại. Tôi đã gọi next()phương thức nhiều lần trong mã


0

Vấn đề của tôi là tôi đã setIntervalchạy, trong đó có một if/elsekhối, trong đó clearIntervalphương thức nằm trong 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 {
            . . .

Đặt clearIntervaltrước khi if/elsethực hiện các mẹo.


0

Trong trường hợp của tôi, trong một vòng lặp, tôi đã đặt res.render()như vậy có thể đã cố gắng gọi nhiều lần.


-1

Tất cả tôi phải làm trong trường hợp lỗi này là res.end ().

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

Vấn đề khác bạn có thể gặp phải là có mã sau res.json và res. viết. Trong trường hợp này, bạn cần sử dụng return để dừng thực thi sau đó.

 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 
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.