Node Express 中的 res.sendfile 传递数据

新手上路,请多包涵

有什么方法可以从 Node.JS 应用程序重定向到 HTML 文件,例如: res.sendFile express 并将 JSON 数据传递到 html 文件?

原文由 user3393991 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 820
2 个回答

您从给定的请求中得到一个响应。您可以将多个事物组合成一个响应,或者要求客户端发出单独的请求以获取不同的事物。

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

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

或者,如果你真的想这样做,你可以将 HTML 文件读入内存,使用某种 .replace() 操作来插入你自己的数据,然后 res.send() 结果改变了文件。

原文由 jfriend00 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

如果您不关心 “为什么” ,请跳到底部

让我先描述一下为什么 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());
   });
});

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

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

解决方案

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

注意:如评论中所述,原始解决方案可能会出现失败的边缘情况。为了解决这个问题,我添加了 换行 包以确保数据块在新行发出。

 const Transform = require('stream').Transform;
const parser = new Transform();
const newLineStream = require('new-line');

parser._transform = function(data, encoding, done) {
  let str = data.toString();
  str = str.replace('<html>', '<!-- Begin stream -->\n<html>');
  str = str.replace('</body>', '<script>var data = {"foo": "bar"};</script>\n</body>\n<!-- End stream -->');
  this.push(str);
  done();
};

// app creation code removed for brevity

app.use('/index.html', (req, res) => {
    fs
      .createReadStream('../public/index.html')
      .pipe(newLineStream())
      .pipe(parser)
      .pipe(res);
});

原文由 Ryan Wheale 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题