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

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


当前回答

我简单地添加了return关键字: 返回res.redirect(“/”);它成功了!

其他回答

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

为了更深入地理解,它看起来像这样的代码;

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")之前

希望这是有意义的,欢迎:)

这个问答中的一些答案是错误的。公认的答案也不是很“实用”,所以我想发布一个答案,用更简单的术语解释事情。我的答案将涵盖99%我看到的反复发布的错误。对于错误背后的实际原因,请查看公认的答案。


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

这个错误信息:

错误:发送后不能设置报头。

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

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

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

当这些res函数被调用时,路由回调将不会返回。它将继续运行,直到到达函数或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.
    });
}

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

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

在代码示例中,我们有一个异步函数(findOneAndUpdate())。如果没有错误(err),将调用findOneAndUpdate()。因为这个函数是异步的,所以res.json(doc1)将被立即调用。假设findOneAndUpdate()中没有错误。else中的res.json(doc2)将被调用。现在已经发送了两个响应,并且出现了“不能设置标题”错误消息。

在这种情况下,修复方法是删除res.json(doc1)。为了将两个文档都发送回客户端,else中的res.json()可以写成res.json({article: doc1, user: doc2})。

我面对这个错误了几天,发现是我的jwt过期了,在这种情况下,它不能设置头文件。

检查你的JWT的有效期

在我的例子中,它是一个全局拦截器,设置无缓存头。

Express中的res对象是Node.js的http的子类。ServerResponse(读取http.js源代码)。你可以调用res.setHeader(name, value),直到你调用res.writeHead(statusCode)。在writeHead之后,头被烘焙进去,你只能调用res.write(data),最后调用res.end(data)。

错误“错误:发送后无法设置报头”意味着您已经处于Body或Finished状态,但某些函数试图设置报头或statusCode。当您看到此错误时,请尝试查找在已经写入部分正文之后试图发送头的任何内容。例如,查找意外调用两次的回调,或者在正文发送之后发生的任何错误。

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

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

响应必须在头部,并保持在头部:

res.writeContinue () res.statusCode = 404 res.setHeader(名称、值) res.getHeader(名字) res.removeHeader(名字) res.header(key[, val]) res.charset = 'utf-8'(仅限Express;只影响特定于express的方法) res.contentType(类型)(仅适用于Express)

Response必须在Head中并成为Body:

作家(雕像,[原因],[标题])

Response可以在Head/Body中任意一个,并保留在Body中:

res.write (chunk, encoding =‘utf8)

Response可以在Head/Body中任意一个,变成Finished:

res.end((数据),(编码))

响应可以在Head/Body中任意一个,并保持当前状态:

res.addTrailers(头)

响应必须在头部,成为完成:

return next([err]) (Connect/Express only) Any exceptions within middleware function(req, res, next) (Connect/Express only) res.send(body|status[, headers|status[, status]]) (Express only) res.attachment(filename) (Express only) res.sendfile(path[, options[, callback]]) (Express only) res.json(obj[, headers|status[, status]]) (Express only) res.redirect(url[, status]) (Express only) res.cookie(name, val[, options]) (Express only) res.clearCookie(name[, options]) (Express only) res.render(view[, options[, fn]]) (Express only) res.partial(view[, options]) (Express only)