Node.js在发送标题后无法设置标题引入res.render()后出错

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js在发送标题后无法设置标题引入res.render()后出错相关的知识,希望对你有一定的参考价值。

我有这段代码:

   app.post('/pst', function(req, res) {
            var data = req.body.convo;

            res.render('waiting.ejs');  //ADDED THIS

            myFunc(data).then(result => {


            res.render('success.ejs');  //THEN THIS

            //---------------------------------
            //clever way to send text file to client from the memory of the server
            var fileContents = Buffer.from(result, 'ascii');
            var readStream = new stream.PassThrough();
            readStream.end(fileContents);
            res.set('Content-disposition', 'attachment; filename=' + fileName);
            res.set('Content-Type', 'text/plain');
            readStream.pipe(res);
            //--------------------------------------

            }).catch( .....

我评论为“从服务器内存发送文件的聪明方式”的代码来自这篇文章:Node Express.js - Download file from memory - 'filename must be a string'

它的作用是从内存中获取一个字符串,并将其作为.txt文件提供给客户端。

这段代码以前有用。

然后我决定添加res.render('waiting.ejs');线,我得到了这个错误:

Error: Can't set headers after they are sent.

然后我尝试在代码将.txt文件发送到客户端之前和之后添加另一个res.render()[在本例中为res.render('success.ejs');]。

错误仍然存​​在。此外,没有重定向到success.ejs,换句话说,res.render('success.ejs');从来没有工作过,尽管它是否在那段代码之前放置。

答案

   app.post('/pst', function(req, res) {
            var data = req.body.convo;

            myFunc(data).then(result => {


          

            //---------------------------------
            //clever way to send text file to client from the memory of the server
            var fileContents = Buffer.from(result, 'ascii');
            var readStream = new stream.PassThrough();
            readStream.end(fileContents);
            res.set('Content-disposition', 'attachment; filename=' + fileName);
            res.set('Content-Type', 'text/plain');
            readStream.pipe(res);
             res.redirect(`/success`);  //THEN THIS
            //--------------------------------------

            }).catch( .....
另一答案

你必须检查express.js源代码(here):

res.render = function render(view, options, callback) {
  var app = this.req.app;
  var done = callback;
  var opts = options || {};
  var req = this.req;
  var self = this;

  // support callback function as second arg
  if (typeof options === 'function') {
    done = options;
    opts = {};
  }

  // merge res.locals
  opts._locals = self.locals;

  // default callback to respond
  done = done || function (err, str) {
    if (err) return req.next(err);
    self.send(str);
  };

  // render
  app.render(view, opts, done);
};

您可以看到,当您使用res.render()方法时,它会将完成的回调传递给app.render(...)source code),然后它会将done传递给tryInitView等。

最后,它会在成功的情况下用done调用str回调,如果失败则调用err。然后它会在res.send()回调中触发done,这会阻止你在此之后设置标题。

另一答案

res.render()函数编译你的模板,在那里插入locals,并从这两件事创建html输出。这就是错误来临的原因。不要使用它两次因为它发送响应。

以上是关于Node.js在发送标题后无法设置标题引入res.render()后出错的主要内容,如果未能解决你的问题,请参考以下文章

node.js创建服务,发送请求后返回数据

res.send 发送后无法设置标头

res.sendFile 不是 Node.js 的函数

如何在 node.js (express) 中全局设置内容类型

如何发送 POST 请求以响应 node.js Express?

关闭 MySQL 后 Node.js 进程无法恢复,然后再打开