错误:将标头发送到客户端后无法设置标头

Error: Can't set headers after they are sent to the client

提问人:DjangoRocks 提问时间:8/12/2011 最后编辑:Antti Haapala -- Слава УкраїніDjangoRocks 更新时间:11/14/2023 访问量:1975616

问:

我对 Node.js 相当陌生,我遇到了一些问题。

我正在使用 Node.js 4.10 和 Express 2.4.3。

当我尝试访问 http://127.0.0.1:8888/auth/facebook 时,我将被重定向到 http://127.0.0.1:8888/auth/facebook_callback

然后,我收到以下错误:

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)

以下是我的代码:

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

我可以知道我的代码有什么问题吗?

JavaScript 节点 .js Express

评论

11赞 julian soro 4/29/2017
谷歌向我发送了这个问题,但较新版本的 ExpressJS 有 res.headersSent 布尔值,可用于检查设置/发送标头是否安全
0赞 shi11i 11/30/2011
来自 VisionMedia 的简单答案:github.com/visionmedia/express/issues/634
0赞 Fom 6/6/2022
对于排查此错误的其他人:如果您在路由中使用通配符,请确保将此类路由放在它们可能捕获的任何其他路由之后。

答:

53赞 Peter Lyons 8/13/2011 #1

很多人都遇到了这个错误。这与异步处理混淆了。最有可能的是,您的某些代码在第一个 tick 中设置标头,然后在将来的 tick 中运行异步回调。在这两者之间,发送响应标头,但随后进一步的标头(如 30X 重定向)尝试添加额外的标头,但为时已晚,因为响应标头已经传输。

我不确定究竟是什么原因导致了您的错误,但将任何回调视为需要调查的潜在区域。

一个简单的技巧来简化你的代码。摆脱并直接在您的顶级范围内调用。app.configure()app.use

另请参阅 everyauth 模块,该模块支持 Facebook 和十几个其他第三方身份验证提供商。

评论

0赞 Peter Lyons 12/24/2011
30X 重定向是 HTTP 响应代码。w3.org/Protocols/rfc2616/rfc2616-sec10.html代码 300-399 是重定向的不同变体,其中 302 和 301 通常用于将客户端发送到备用 URL。当您在 node 中执行 response.redirect(...) 时,响应中将发送 30X 重定向标头。
4赞 Janac Meena 3/17/2018
哦。我想象着连续 30 次重定向之类的
1606赞 4 revs, 3 users 88%yonran #2

Express 中的对象是 Node.js 的 http 的子类。服务器响应读取 http.js 源)。您可以随心所欲地拨打电话,直到您拨打 。之后,标头被烘焙,你只能调用 ,最后。resres.setHeader(name, value)res.writeHead(statusCode)writeHeadres.write(data)res.end(data)

错误“错误:发送后无法设置标头”表示您已处于“正文”或“已完成”状态,但某些函数尝试设置标头或状态代码。当您看到此错误时,请尝试查找在已写入某些正文后尝试发送标头的任何内容。例如,查找意外调用两次的回调,或发送正文后发生的任何错误。

在本例中,您调用了 ,这导致响应变为 Finished。然后你的代码抛出了一个错误(是)。并且由于错误发生在您的实际(而不是回调中),因此 Connect 能够捕获它,然后尝试发送 500 错误页面。但是由于标头已经发送,Node.js 抛出了您看到的错误。res.redirect()res.reqnullfunction(req, res, next)setHeader

Node.js/Express 响应方法的完整列表以及何时必须调用它们:

响应必须在 Head 中并保持在 Head 中:

  1. res.writeContinue()
  2. res.statusCode = 404
  3. res.setHeader(name, value)
  4. res.getHeader(name)
  5. res.removeHeader(name)
  6. res.header(key[, val]) (仅限 Express)
  7. res.charset = 'utf-8'(仅限 Express;仅影响特定于 Express 的方法)
  8. res.contentType(type)(仅限 Express)

响应必须在 Head 中,并变为 Body

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

响应可以在头部/身体中,并保持在正文中:

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

响应可以在 Head/Body 中任一,并变为 Finished

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

响应可以处于头部/身体状态,并保持其当前状态:

  1. res.addTrailers(headers)

响应必须在 Head 中,并变为 Finished

  1. return next([err])(仅限 Connect/Express)
  2. 中间件中的任何异常(仅限 Connect/Express)function(req, res, next)
  3. res.send(body|status[, headers|status[, status]]) (仅限 Express)
  4. res.attachment(文件名)(仅限 Express)
  5. res.sendfile(path[, options[, callback]]) (仅限 Express)
  6. res.json(obj[, headers|status[, status]]) (仅限 Express)
  7. res.redirect(url[, status]) (仅限 Express)
  8. res.cookie(name, val[, options]) (仅限 Express)
  9. res.clearCookie(name[, options]) (仅限 Express)
  10. res.render(view[, options[, fn]]) (仅限 Express)
  11. res.partial(view[, options]) (仅限 Express)

评论

57赞 Tony Gutierrez 5/7/2015
是的,检查是否调用 next() 或其他 cb 两次。
5赞 Korhan Ozturk 12/4/2015
快递链接似乎死了
54赞 KLoozen 1/23/2016
还要注意这个经典错误:res.redirect() 不会停止语句执行......所以在它之后回来。否则,可能会执行其他代码,这可能会无意中导致著名的标头错误。谢谢你的解释!
0赞 thethakuri 6/1/2016
在回调结束时使用 return 通常是一个好主意,以避免这种情况
12赞 illcrx 12/31/2016
我在中间件中犯了一个非常小的错误,我以前没有,感谢这给我指出了错误!returnnext()
159赞 Lance 10/17/2011 #3

我也遇到了这个错误一段时间。我想(希望)我已经把我的头包起来了,想写在这里作为参考。

当您使用该方法将中间件添加到 connect 或 express(基于 connect 构建)时,您将项目附加到 in connect(至少与当前 ,看起来与本文的 github 完全不同)。当服务器收到请求时,它会循环访问堆栈,调用该方法。app.useServer.prototype.stacknpm install connect(request, response, next)

问题是,如果在其中一个中间件项中写入响应正文或标头(出于某种原因,它看起来像是非此即彼),但没有调用 response.end() 并且您调用 next(),那么随着核心方法的完成,它会注意到:Server.prototype.handle

  1. 堆栈中没有更多项目,和/或
  2. 这是真的。response.headerSent

因此,它会抛出一个错误。但它抛出的错误只是这个基本响应(来自连接源代码:http.js

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

就在那里,它调用了 ,您可能已经在方法中设置了它,而无需调用 response.end(),如下所示:res.setHeader('Content-Type', 'text/plain');render

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

一切需要结构化的方式是这样的:

良好的中间件

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

有问题的中间件

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

有问题的中间件设置响应头而不调用和调用,这会混淆 connect 的服务器。response.end()next()

评论

10赞 qodeninja 12/7/2012
+1 这是一个很好的解释,但是当您使用 res.redirect() 时的情况呢?当中间件尝试根据某些条件进行重定向时,我经常遇到这个问题。根据“好的中间件”示例,中间件不应该重定向吗?
0赞 iQ. 10/30/2014
你知道我遇到了这个确切的问题,因为你称之为有问题的中间件,但是我需要一种情况,我返回响应,但想在单独的控制器中作为链的一部分进行进一步的处理,我该如何去抑制这个错误?
5赞 blented 5/17/2014 #4

就我而言,是 304 响应(缓存)导致了问题。

最简单的解决方案:

app.disable('etag');

如果您想要更多控制权,请在此处提供替代解决方案:

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

评论

0赞 Dileep stanley 7/27/2014
就我而言,还有 304 响应。我使用纤维进行加工。无论如何,您的答案都有很大帮助。谢谢
0赞 mattwilsn 5/24/2016
谁能解释一下删除 etag 标头的含义是什么?
5赞 blented 5/25/2016
ETag 允许服务器不发送未更改的内容。关闭它将关闭 此功能。ETag 维基百科条目 (en.wikipedia.org/wiki/HTTP_ETag) 有一个更长的解释。
74赞 ergusto 2/14/2015 #5

我遇到了同样的问题,并意识到这是因为我在没有语句的情况下调用,因此该函数也紧随其后被调用:res.redirectreturnnext

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

这应该是:

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

评论

0赞 corysimmons 8/22/2020
如果返回,则无法访问 next()。
0赞 ergusto 8/29/2020
@corysimmons我不明白你的意思。目的是在调用重定向时不调用。不打算在返回后再打电话。next
5赞 Mike 5/19/2015 #6

对于任何来到这里并且其他解决方案都无济于事的人来说,在我的情况下,这体现在处理图像上传但不处理时的路由上,因此,如果上传时间过长并超时,当在发送超时响应后触发回调时,调用 res.send() 会导致崩溃,因为标头已经设置为考虑超时。

通过设置一个非常短的超时时间并用相当大的图像击中路线,这很容易重现,每次都会重现崩溃。

评论

4赞 2/2/2019
您如何处理超时以避免这种情况?
5赞 Zoltán 6/2/2015 #7

就我而言,当我没有在 React 组件的回调中取消订阅频道时,React 和 postal.js 就发生了这种情况。componentWillUnmount

21赞 randomness 7/4/2015 #8

我对这个问题感到困惑,它是由于处理回调时的粗心错误而发生的。未返回的回调会导致响应被设置两次。!

我的程序有一个代码,用于验证请求和查询数据库。验证是否存在错误后,我回调了带有验证错误的索引.js。 如果验证通过,它将继续以成功/失败的方式命中数据库。

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

发生的事情是:如果验证失败,回调将被调用并设置响应。但没有归还。所以它仍然继续该方法转到 db 并点击成功/失败。它再次调用相同的回调,导致响应现在被设置两次。

所以解决方案很简单,你需要“返回”回调,这样一旦发生错误,方法就不会继续执行,因此设置一次响应对象

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

评论

1赞 6/14/2016
谢谢!事实证明,这也是我的问题。只是做了一个ctrl + f,发现一个没有后面的,最终导致被调用两次。callback(...)return;res.send(...)
4赞 Adam Boostani 11/5/2015 #9

只是靠了这个。您可以通过此函数传递响应:

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();
});
24赞 Trojan 9/28/2016 #10

当您在发送响应后传递语句时,将收到这种类型的错误。

例如:

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

将导致您看到的错误,因为一旦发送了响应,将不会执行以下操作。res.send

如果你想做任何事情,你应该在发送响应之前做。

13赞 Surendra Babu Parchuru 3/8/2017 #11

有时,当您尝试在res.end或res.send之后调用next()函数时,可能会遇到此错误,如果函数中的res.send或res.end之后有next(),请尝试删除。 注意:这里的next()表示在用你的响应(即res.send或res.end)响应客户端后,你仍然试图执行一些代码来再次响应,所以这是不合法的。

例:

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

从上述功能中删除,它将起作用。next()

评论

2赞 Rodrigo 2/2/2021
事实上,这就是我的情况,中间件中的一个挥之不去的调用导致了这个问题。我花了将近一个小时才意识到......next()
3赞 ASHISH R 4/28/2017 #12

添加此中间件,它将起作用

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();
});
4赞 Ankit Manchanda 7/12/2017 #13

当响应被传送到客户端并且您再次尝试给出响应时,就会发生这种情况。您必须在代码中检查您再次向客户端返回响应的某个地方,这会导致此错误。当您想要返回时,检查并返回一次响应。

229赞 Mika Sundland 1/6/2018 #14

本问答中的一些答案是错误的。被接受的答案也不是很“实用”,所以我想发布一个用更简单的术语解释事情的答案。我的答案将涵盖我一遍又一遍地看到的 99% 的错误。有关错误背后的实际原因,请查看已接受的答案。


HTTP 使用一个周期,每个请求需要一个响应。当客户端发送请求(例如 POST 或 GET)时,服务器应该只向它发送一个响应。

此错误消息:

错误:发送标头后无法设置标头。

通常在为一个请求发送多个响应时发生。确保每个请求仅调用一次以下函数:

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

(还有一些很少使用的,检查接受的答案)

调用这些 res 函数时,路由回调不会返回。它将继续运行,直到它到达函数或 return 语句的末尾。如果要在发送响应时返回,可以这样做:.return res.send()


以以下代码为例:

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

当 POST 请求发送到 /api/route1 时,它将运行回调中的每一行。发送标头后无法设置标头错误消息将引发,因为调用了两次,这意味着发送了两个响应。res.json()

每个请求只能发送一个响应!


上面代码示例中的错误是显而易见的。一个更典型的问题是,当你有多个分支时:

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

此带有附加回调的路由在数据库中查找公司。当对不存在的公司进行查询时,我们将进入分支机构并发送 404 响应。之后,我们将继续执行下一条语句,该语句也会发送响应。现在我们已经发送了两个响应,将出现错误消息。我们可以通过确保只发送一个响应来修复此代码:else if

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

或者在发送响应时返回:

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

一个大罪魁祸首是异步函数。以这个问题中的函数为例:

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

这里我们在代码示例中有一个异步函数 ()。如果没有错误,将调用 ()。由于此函数是异步的,因此将立即调用。假设 中没有错误。然后调用 in。现在已发送两个响应,并出现“无法设置标头”错误消息。findOneAndUpdate()errfindOneAndUpdate()res.json(doc1)findOneAndUpdate()res.json(doc2)else

在这种情况下,解决方法是删除 .要将两个文档发送回客户端,可以将 in the else 写成 .res.json(doc1)res.json()res.json({ article: doc1, user: doc2 })

评论

3赞 Genovo 7/1/2018
您位于异步函数中,并且必须returnres.json
1赞 Maihan Nijat 9/7/2018
我的问题是在for循环中使用。res.send
0赞 Mary Obiagba 1/25/2021
非常感谢米卡的解释。我有product().findById().then().then().catch()。两个 .then() 方法中都有一个 res.status().json。删除一个解决了将标头发送到客户端后无法设置标头的问题。
1赞 Janac Meena 3/20/2018 #15

在 Typescript 中,我的问题是我在收到消息后没有关闭 websocket 连接。

WebSocket.on("message", (data) => {
    receivedMessage = true;
    doSomething(data);
    localSocket.close(); //This close the connection, allowing 
});
3赞 Sanjay 4/28/2018 #16

如果你没有得到上面的帮助:对于菜鸟 此错误背后的原因是多次发送请求,让我们从某些情况中了解:- 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();   
        }

` 在上面调用 next() 两次会引发错误

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

这里的回复是发送两次,检查你是否已经发送了回复

1赞 rharding 6/19/2018 #17

我在嵌套承诺时遇到了这个问题。promise 内部的 promise 将向服务器返回 200,但随后外部 promise 的 catch 语句将返回 500。一旦我解决了这个问题,问题就消失了。

评论

0赞 saurabh 3/23/2020
你到底是怎么解决这个问题的?我对承诺也有同样的问题。我无法避免嵌套它们......那么如何在 return 语句停止执行呢?
1赞 Mr. Ratnadeep 7/9/2018 #18

就我而言,它是由于多个回调而发生的。我在代码中多次调用方法next()

1赞 Nick Synev 8/24/2018 #19

nuxt 来到这里,问题出在组件的方法上,我忘了承诺哪个正在获取数据并在那里设置标头。asyncDatareturn

-1赞 coder 9/7/2018 #20

如果出现此错误,我所要做的就是res.end()。

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

您可能面临的另一个问题是res.json和 res. write 之后有代码。在这种情况下,您需要使用 return 在此之后停止执行。

 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 
};
7赞 KNDheeraj 1/12/2019 #21

请检查您的代码是否为单个请求返回多个语句。就像我遇到这个问题时一样......res.send()

我在我的restify节点应用程序中遇到了这个问题。错误在于

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

我正在使用 switch 处理各种情况,而无需写中断。对于那些不太熟悉开关情况的人知道,没有中断,返回关键字。无论如何,都会执行 case 下的代码和下一行代码。因此,即使我想发送单个,由于这个错误,它返回了多个语句,这提示了res.sendres.send

错误:将标头发送到客户端后无法设置标头。

通过添加此方法或在每个方法之前使用 return 来解决此问题,例如res.send()return res.send(200)

switch (status) {
    case -1:
      res.send(400);
      break;
    case 0:
      res.send(200);
      break;
    default:
      res.send(500);
      break;
}
3赞 Naved Ahmad 2/23/2019 #22

这很可能更像是一个节点问题,99% 的时间它是一个双重回调,导致你响应两次,或者 next()ing 两次等等,该死的。它解决了我在循环中使用 next() 的问题。从循环中删除 next() 或停止多次调用它。

评论

0赞 Luke Schoen 6/28/2020
我有同样的错误,这是因为在同一个中间件函数中,我调用了两个函数,每个函数都调用了 .我通过创建第二个中间件函数并将其中一个函数移动到其中来修复该错误,因此每个中间件函数中只有一个调用。这是解决问题的提交:github.com/DataHighway-DHX/faucet/commit/...next()next()
13赞 Krishnadas PC 6/5/2019 #23

如果您使用的是回调函数,请在块之后使用。这是可能发生此错误的情况之一。returnerr

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

在 Node 版本和 express 上测试v10.16.04.16.4

17赞 Badr Bellaj 10/7/2019 #24

当您发送 2 个响应时,会发生此错误。例如:

if(condition A)
{ 

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

}

if (condition B){

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

想象一下,如果由于某种原因条件 A 和 B 为真,那么在第二秒内,您将收到该错误render

2赞 trustidkid 10/26/2019 #25

当我尝试在循环函数中发送响应时,我遇到了类似的错误。简单的解决方案是将

res.send('发送响应');

由于您只能发送一次响应标头,因此无法循环。

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

20赞 Emmanuel Benson 11/14/2019 #26

我只是简单地添加了关键字,例如:它奏效了!returnreturn res.redirect("/great");

22赞 Nagender Pratap Chauhan 12/19/2019 #27

错误在 RND 之后自行查找:

1)我的错误代码:

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

2) 我的成功代码

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

不同之处在于我使用了 sendStatus() 而不是 status()。

评论

1赞 Vivek Sharma 1/4/2022
为什么首先使用 sendStatus?
0赞 Nagender Pratap Chauhan 1/7/2022
基本上是发送前端的状态。
0赞 Mike K 1/14/2020 #28

我的问题是我有一个运行,它有一个块,其中方法在:setIntervalif/elseclearIntervalelse

      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 {
            . . .

把前面的就行了。clearIntervalif/else

1赞 Sina Abedi 2/12/2020 #29

我遇到了同样的问题,这是由猫鼬引起的。

要解决此问题,您必须启用 ,以便您可以将 : 添加到您的代码中,从而启用使用 .Promisesmongoose.Promise = global.Promisenative js promises

这种解决方案的其他替代方案是:

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

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

但是您需要先安装这些软件包。

0赞 Hasan Sefa Ozalp 2/20/2020 #30

就我而言,在一个循环中,我放置了 so 可能已尝试多次调用。res.render()

8赞 Mohammed Ramadan 7/17/2020 #31

还有其他原因导致此错误,当您没有在 res.send、res.json 等前面添加 return 关键字时......

1赞 HandyPawan 8/5/2020 #32

Process.env 不会更改,因此它不得用于访问每个请求的环境变量,其值可能会根据每个请求而更改。 因此,如果用户生成了一个应用程序进程,但不是作为处理请求的一部分,则该应用程序进程将不会在操作系统级别的环境变量中存储每个请求的环境变量。 因此,使用此代码来存储进程环境,并且您的程序会成功运行。

    const port = process.env.PORT || 2000;
    
    app.listen(port,()=>{
        console.log("Server running at port 2000");
    })
5赞 Farbod Aprin 1/15/2021 #33

请在 res.send(“您的结果”) 之前搜索 if in your app.get to not set status before(“your result”);

我刚刚删除了:

res.sendStatus(200);

响应在!!之后起作用

res.send("your result");
1赞 SanRaph 4/22/2021 #34

就我而言,当我不使针对 mongodb 模式运行的函数成为这样的异步函数时,这种情况会反复出现,我得到这个而不是它是异步的,因为 this.password 来自这个函数正在运行的对象,我们正在从数据库中提取。technicianAuthSchema.methods.matchPasswords = function(password) { return await bcrypt.compare( password, this.password ); };Logged error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client technicianAuthSchema.methods.matchPasswords = async function(password) { return await bcrypt.compare( password, this.password ); };

2赞 Rupak 5/1/2021 #35

检查您的代码。对我来说,我在同一个 if 语句中使用了两次 res.status。第一个设置标头状态,第二个尝试更改它,这导致了问题。

评论

0赞 Hamza Muazzam 7/20/2022
谢谢伙计。 但是res.end()和res.send()有什么区别,我认为两者都终止了api调用。res.send() 发送响应并停止函数,而 res.end() 仅终止函数而不发送响应。这是真的吗?
3赞 Marvin 6/12/2021 #36

问题存在于路由中,以使事情易于理解,一旦您已经从客户端发送了响应,您就不能为下一个后续块设置下面的任何其他函数,这也与 JavaScript 的同步有关,/auth/facebook

为了深入理解,它看起来像这个代码;

async function getRequest(){
   let data = await API.get();
   return data;
   let json = data.json(); // will not read this line
}

在您的案子上,并且必须放在之前console.log("ok cool.");console.log(res['req']['session'])res.redirect("/great")

enter image description here

希望这是有道理的,欢迎:)

3赞 Engin Karataş 8/27/2021 #37

如果在一个 API 调用中使用两个 res.end() 函数,则会显示此错误

例如

  app.post("/auth", function (request, res) {
    var username = request.body.username;
    var password = request.body.password;
    if (username && password) {
      let sql =
        "SELECT username, worker_name, worker_surname, id FROM workers where username = ? AND password=?";
      con.query(sql, [username, password], function (error, results, fields) {
        if (results.length > 0) {
          res.status(200).send(results);
          res.end();
  
        }
        res.status(404).send("Incorrect Username and/or Password!");
      });
    } else {
      res.send("Please enter Username and Password!");
    }
    res.end();

  });
5赞 genericUser 9/29/2021 #38

较新版本的 Node 支持 res.headersSent 布尔表达式。您可以使用它来验证是否已发送响应:

if (!res.headersSent) // if doesn't sent yet
    res.status(200).send({ "message": "This is a message" })

注意!虽然这有效并回答了问题,但这不是解决问题的正确方法,因此不推荐!

多次发送响应表明您的代码中存在应修复的问题(这与在函数中一个接一个地使用两个 return 语句相同,这是一个错误)。

1赞 Shallon Kobusinge 4/6/2022 #39

我有问题 这就是我正在做的事情

const user  = await User.findOne({_id: req.params.id})

所以我不得不将 findOne 更改为 findById,它为我解决了问题

const user = await User.findById(req.params.id)
1赞 Johan Tamayo 5/6/2022 #40

我遇到了同样的错误,发现我的解决方案是将我所有的 sendStatus 代码行更改为 status。

// old
res.sendStatus(200);

// new 
res.status(200);
3赞 Rajanboy 5/19/2022 #41

有时仅写作是不够的。 几个小时以来,我发现我们有时必须返回响应。 喜欢这个 res.status(200).json({success: 'user authenticated');return

return res.status(200).json({success: 'user authenticated');

这样它就可以在某个条件语句中随时终止,并且不会运行其他 .

评论

0赞 DamonWu 9/22/2022
是的,对于nextjs项目,API最好有一个关键字或你的API响应。return
0赞 M Fuat 6/21/2022 #42

就我而言,它是一个全局拦截器,它设置了无缓存标头。

0赞 GoldPaintedLemons 6/30/2022 #43

显然,发生这种情况的原因有很多。许多都很复杂,但我的情况是一个非常简单的错误。

检查您是否具有正确的表单方法。默认值为 GET,我不知何故忘记指定。可以想象,我的 GET 路由逻辑在处理设计为由我的 POST 路由逻辑解析的 req.body 数据方面做得很差。

1赞 Auguste 7/5/2022 #44

就我而言,我必须添加 Promise 方法以链接响应。所以我的代码如下所示:.then()

 app.post(`${api}/categories`, (req, res) => {
const category = new Category({
    ....
});
category.save().then(c => {
    res.status(201).json(c)
}).catch((err) => {
    res.status(500).json({
        ...
    })
});

})

1赞 holabisii 9/26/2022 #45

我遇到了几天的错误,发现是我的 jwt 过期了,在那个场景中它无法设置标头。

检查 JWT 到期日期

1赞 otumian Empire 10/21/2022 #46

我在使用邮递员时遇到了同样的错误。我注意到请求正文(数据)的格式不正确。错误指向我在路由上传递的中间件。当我删除一个中间件时,它意味着下一个中间件。

3赞 Brijal Kansara 11/14/2022 #47

我有同样的问题。对我来说,我有 2 个res.json(事件)给了我这个错误。

res.json(savedEvent);
res.json({ event });

我们应该只传递一个响应就可以了。

res.json(event);
0赞 nasmus shahadat 11/7/2023 #48

不要在一个 API 中使用多个。只需使用一次,这个问题就会得到解决。resres

0赞 Ashish Kumar 11/14/2023 #49

问题是,代码中正在对res(Response)的标头进行多次修改。这是不允许的,因为 express 会在第一次调用时将数据发送到客户端。所以第二个失败了。如果可以绕过每个案例只有 1 个标头,它将解决问题。它可以通过条件语句完成,或者在分配标头后返回,或者在代码结束之前完全处理之前不设置错误(以最适用者为准)

对于以下代码,我收到相同的错误“ERR_HTTP_HEADERS_SENT”:

const createPrice = async function (request, response) {
  const data = request.body;
  var maxID = 9999;
  const result = await pool.query("SELECT MAX(id) FROM pricing");
  maxID = result.rows[0].max + 1;
  pool.query(
    "Insert into pricing (id, price, discounts) values ($1, $2, $3) RETURNING *",
    [maxID, data.price, data.discounts,],
    (error, results) => {
      if (error) {
        throw error;
      }
      response.status(201).send(`Rate Card ID: ${maxID} Created`);
          }
        }
      );
    };

对我来说,问题似乎是我正在处理中间件中的错误,所以发生的事情是响应的正文被设置在 2 个地方,第一个在throw error;response.status(201).send();

我认为让我的代码工作所需的最小更改是放置一个并将我的放入其中。因此,要请求的两种数据设置中只有一种有效。elseresponse.send()

不知何故,单独放置 return 或 headerSent 支票对我不起作用。但我最终使用了上述解决方案的组合来更好地处理问题。在这里,我最后的改变:

(error, results) => {
  if (error) {
    throw error;
  } else if (!response.headersSent) {
    // if doesn't sent yet
    return response
      .status(201)
      .send(`Rate Card ID: ${data.maxID} Created`);
  }
}