为什么我的快递路由器只在我发送JSON时崩溃而不是在我发送文本时崩溃?

时间:2017-03-12 18:11:16

标签: node.js express

statusRouter.route('/')
.all(function(req,res,next){
  res.writeHead(200, {'Content-Type': 'application/json'});
  next();
})
.get(function(req, res, next) {
    res.json({
       name : "xyz"
     });
});

这会崩溃 - 标题无法在发送后设置。
但问题是,这有效:

statusRouter.route('/')
.all(function(req,res,next){
  res.writeHead(200, {'Content-Type': 'text/plain'});
  next();
})
.get(function(req, res, next) {
    res.end("xyz");
});

注意:如果我在发送JSON的第一种情况下删除了writeHead函数,它也会开始工作。为什么当我写一个writeHead时它不起作用?这件事让我发疯,任何人都可以解释为什么会这样?
P.S我正在使用我自己的路由器使用快速生成的应用程序。

2 个答案:

答案 0 :(得分:2)

Express res.writeHead()res.end()都不是由Express实现的,而是由Node.js http模块实现的。

其文档说明res.end()

  

如果指定了data,则相当于调用response.write(data, encoding)后跟response.end(callback)

所以res.end("xyz")简称:

res.write("xyz");
res.end();

对于res.write()文档说明:

  

如果调用此方法并且尚未调用response.writeHead(),则它将切换到隐式标头模式并刷新隐式标头。

所以res.end("xyz") 实际简称:

if (! res.headersSent) {
  res.writeHead(...);
}
res.write("xyz");
res.end();

这意味着在使用res.writeHead()之前,在您自己的代码中发出res.end()是完全可以的。在内部,http模块会知道您已经刷新了标题,因此它不会再次执行(因此可以防止您获得的错误)。但是,一旦调用writeHead(),您就无法设置不同的标头或更改现有的标头。

现在,res.json()是另一回事:这不是http模块的一部分,而是Express本身的一部分。由于它用于发送JSON响应,因此会将内容类型标题设置为application/json(因此您不必这样做)。

但这只有在尚未发送标题时才有效:您已经发出标题时无法设置标题。这就是您收到错误的原因。

如果要在Express中设置特定标头,请使用res.set()

答案 1 :(得分:1)

Express按照添加顺序评估其路线。这意味着将首先执行传递给pip3 install ...的路由处理程序。在此处理程序中,写入响应头,然后.all()告诉Express继续迭代其路由列表以获得另一个可能的匹配路由。

然后匹配尝试发送JSON响应的next()路由处理程序。但是,.get() 隐式发送响应头,并将作为JSON传递的值写入响应并结束响应。这就是为什么您看到有关.json()被多次调用的错误。