node.js/express: 发送后无法设置 headers

node.js/express: Can't set headers after they are sent

尽管网上有大量关于此主题的 Whosebug 问题和文章,none 似乎适用于我的特定应用程序。

router.get('/getFile', (req, res) => {
    console.log("Calling getFile for file " + req.query.serialNumber + ".")
    var serialNumber = req.query.serialNumber;
    let request = new sql.Request(conn);
    request.query('SELECT FileName + \'.\' + FileExtension AS \'File\', FileType, ContentType, SerialNumber, Chart ' +
        'FROM dbo.ChangeFiles ' +
        'WHERE SerialNumber = ' + serialNumber)
        .then(function (recordset) {
            log("Successfully retrieved file " + recordset[0].SerialNumber + " from database.")
            res.writeHead(200, {
                'Content-Type': recordset[0].ContentType,
                'Content-disposition': 'attachment;filename=' + recordset[0].File
            });
            res.send(Buffer(recordset[0].Chart));
        }).catch(function (err) {
            log(err);
            res.send("Issue querying database!");
        });
});

我似乎无法弄清楚如何正确更改 headers 以便它在 res.send 命中之前完成。这很可能是由于 javascript 的异步性质,我还没有正确掌握这一点,但我如何确保 res.writeHead 在 res.send 之前被调用?

非常感谢您查看本文。

当使用 res.writeHead() 时,header 会立即发送给请求者。由于您使用的是 Express 函数 res.send()which also sends over your headers, they have already been sent and you will get an error saying the headers have already been sent. Alternatively, you could use res.end() 不会导致 headers 发送错误,因为它将完成响应并发送传递给它的任何剩余块。

how can I ensure that res.writeHead is called before res.send?

如果您打算使用 res.send(),请将您的 res.writeHead() 调用更改为 res.setHeader() 以在您的响应 object 中设置 header 值。此外,在使用 Express 时,您可以使用 res.status(<statusCode>).

设置响应的 status

我注意到的另一件事是您对 Buffer 的使用。您应该将成功响应处理程序中的 Buffer 创建从 Buffer() 更改为 Buffer.from(),因为 Buffer()deprecated.

router.get('/getFile', (req, res) => {
    console.log("Calling getFile for file " + req.query.serialNumber + ".")

    let serialNumber = req.query.serialNumber
    let request = new sql.Request(conn)
    let query = 'SELECT FileName + \'.\' + FileExtension AS \'File\', FileType, ContentType, SerialNumber, Chart ' +
        'FROM dbo.ChangeFiles ' +
        'WHERE SerialNumber = ' + serialNumber

    request.query(query)
        .then(recordset =>{
            console.log("Successfully retrieved file " + recordset[0].SerialNumber + " from database.")

            let {ContentType, Chart File} = recordset[0]

            // Set Response Status and Headers
            res.status(200)
            res.setHeader('Content-Type', ContentType)
            res.setHeader('Content-Disposition', `attachment;filename=${File}`)            

            return res.send(Buffer.from(Chart))
        }).catch(err => {
            console.log(err);
            return res.status(500).send("Issue querying database!");
        })
})