在Express/Node.js中调试'无法在发送后设置标头'错误的最佳方法是什么?

Ant*_*pos 10 node.js express

我正在尝试调试Can't set headers after they are sentnode.js Express应用程序中的可怕错误.具体来说,我正在使用knox库与s3交谈.

粗略地说,我有这个Express处理程序,使用knox s3client的全局实例:

function foo(req, res) {
    //Region A
    var s3req = global.s3client.get('foo').on('response', function(s3res){
        //Region B
        res.set('content-length', s3res.headers['content-length']); //This will fail
        s3res.on('data', function(chunk){
            res.write(chunk);
        });
    });
    //Region C
    s3req.end();
}
Run Code Online (Sandbox Code Playgroud)

如果我res在区域A中设置任何标题或状态代码,一切正常.如果我尝试区域B中的任何一个,我会得到"无法在发送后设置标头"错误.请注意,我想设置标头res,而不是s3res

据推测response.writeHead,在调用knox s3client的响应回调之前,某处正在调用或触发.是否有一些调试标志或其他方式让Node在调用writeHead时吐出?节点0.10添加了一个response.headersSent,但是通过检查这个标志以确定调用它的位置来填充我的代码和所有第三方库是非常困难的.或者还有其他方法来解决这个问题?

rob*_*lep 12

您可以尝试包含一个简单的中间件,在writeHead调用时将堆栈跟踪转储到stdout :

app.use(function(req, res, next) {
  res.on('header', function() {
    console.trace('HEADERS GOING TO BE WRITTEN');
  });
  next();
});
Run Code Online (Sandbox Code Playgroud)

您必须在可能触发问题的路由/中间件之前插入它.

FWIW,我的猜测是,这个问题是由一些C区发生触发(或者是res.send,res.end,res.json或者res.render是被呼叫存在):

function foo(req, res) {
    //Region A
    var s3req = global.s3client.get('foo').on('response', function(s3res){
        //Region B
        res.set('content-length', s3res.headers['content-length']);
    }); 
    //Region C
}
Run Code Online (Sandbox Code Playgroud)

编辑如果s3res是正确的流,你可以试试这个:

function foo(req, res) {
  global.s3client.get('foo').on('response', function(s3res) {
    s3res.pipe(res);
  }).end();
}
Run Code Online (Sandbox Code Playgroud)

但请注意,S3请求返回的所有标头都将传递给Express响应.