Node Express中的res.sendfile并传递数据

use*_*991 26 javascript node.js express

有没有办法从Node.JS应用程序重定向到HTML文件,如:res.sendFileexpress,并将JSON数据传递给html文件?

Rya*_*ale 28

我知道这已经很晚了,但我想提供一个别人没有提供的解决方案.此解决方案允许将文件流式传输到响应,同时仍允许您修改内容,而无需模板引擎或将整个文件缓冲到内存中.

如果你不关心"为什么",请跳到谷底

让我首先描述为什么res.sendFile对那些不知道的人如此理想.由于Node是单线程的,它通过连续执行大量非常小的任务来工作 - 这包括从文件系统读取并回复http请求.在任何时候,Node都不会停止正在执行的操作,并从文件系统中读取整个内容.它会读一点,做别的事情,多读一点,做别的事情.回复一个http请求和Node中的大多数其他操作也是如此(除非你明确使用sync一个操作的版本 - 比如readFileSync - 如果你可以帮助它,不要这样做,严重的,不要 - 这是自私的) .

考虑10个用户请求同一文件的情况.效率低下的事情是将整个文件加载到内存中,然后使用发送文件res.send().即使它是相同的文件,文件也会在被发送到浏览器之前分别加载到内存10中.然后垃圾收集器需要在每次请求后清理这个混乱.代码将被无辜地写成:

app.use('/index.html', (req, res) => {
   fs.readFile('../public/index.html', (err, data) => {
      res.send(data.toString());
   });
});
Run Code Online (Sandbox Code Playgroud)

这似乎是正确的,它可以工作,但效率非常低.由于我们知道Node以小块的形式处理事情,因此最好的做法是在从文件系统中读取数据时将小块数据发送到浏览器.这些块永远不会存储在内存中,您的服务器现在可以处理更多的流量.这个概念称为流式传输,它就是这样res.sendFile做的 - 它将文件从文件系统直接传输给用户,并为更重要的事情保留内存.以下是您手动执行的操作:

app.use('/index.html', (req, res) => {
    fs.createReadStream('../public/index.html')
    .pipe(res);
});
Run Code Online (Sandbox Code Playgroud)

如果您希望在对文件稍作修改的同时继续将文件流式传输给用户,那么此解决方案适合您.请注意,这不是模板引擎的替代品,而是应该用于在文件流式传输时对文件进行小的更改.下面的代码会将带有数据的小脚本标记附加到HTML页面的主体.它还显示了如何在http响应流中添加或附加内容:

const Transform = require('stream').Transform;
const parser = new Transform();
parser._transform = function(data, encoding, done) {
  const str = data.toString().replace('</body>', '<script>var data = {"foo": "bar"};</script></body>');
  this.push(str);
  done();
};

// app creation code removed for brevity

app.use('/index.html', (req, res) => {
    res.write('<!-- Begin stream -->\n');
    fs
    .createReadStream('../public/index.html')
    .pipe(parser)
    .on('end', () => {
        res.write('\n<!-- End stream -->')
    }).pipe(res);
});
Run Code Online (Sandbox Code Playgroud)

  • 尝试使用此解决方案发送json文件。我在第二次刷新时遇到“错误:结束后写入”。 (2认同)

jfr*_*d00 16

您从给定的请求中获得一个响应.您可以将多个内容组合到一个响应中,也可以要求客户端单独发出请求以获取单独的内容.

如果您要做的是获取HTML文件并通过在其中插入一些JSON来修改它,那么您不能仅仅res.sendFile()因为它只是从磁盘或缓存中读取文件而直接将其作为响应流式传输,提供没有机会修改它.

更常见的方法是使用模板系统,允许您将内容插入HTML文件(通常用您自己的数据替换特殊标记).实际上有数百个模板系统和许多支持node.js的模板系统.node.js的常见选择是Jade(Pug),Handlebars,Ember,Dust,EJS,Mustache.

或者,如果您真的想这样做,您可以将HTML文件读入内存,对其使用某种.replace()操作来插入您自己的数据,然后res.send()生成更改的文件.


小智 5

嗯,它有点旧,但我没有看到任何足够的答案,除了“为什么不”。您确实可以在静态文件中传递参数。这很容易。考虑在您的原点上使用以下代码(使用 express):

    let data = fs.readFileSync('yourPage.html', 'utf8');
    if(data)
    res.send(data.replace('param1Place','uniqueData'));
    //else - 404
Run Code Online (Sandbox Code Playgroud)

现在,例如,只需在yourPage.html 中设置一个 cookie,例如:

    <script>
    var date = new Date();
    document.cookie = "yourCookieName='param1Place';" + 
    date.setTime(date.getTime() + 3600) + ";path=/";
    </script>
Run Code Online (Sandbox Code Playgroud)

您可以在 js 中的任何位置从 yourCookieName中提取uniqueData 的内容

  • 同步很糟糕。要么使用异步版本,要么更好;溪流。见 /sf/answers/2669072871/ (2认同)