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

有什么办法从Node.JS应用程序redirect到一个HTML文件,如: res.sendFile的快递,并传递一个JSON数据到HTML文件?

你从给定的请求得到一个响应。 您可以将多个事物组合成一个响应,或者要求客户端分别发出请求以获得单独的东西。

如果你想要做的是取得一个HTML文件,并通过插入一些JSON来修改它,那么你不能只使用res.sendFile()因为它只是从磁盘或caching读取一个文件,并直接stream作为回应,没有机会修改它。

这样做的更常见的方法是使用一个模板系统,让你插入一个HTML文件的东西(通常用自己的数据replace特殊标签)。 有几百个模板系统,很多都支持node.js。 对于node.js的常见select是Jade,Handlebars,Ember,Dust,EJS,Moustache。

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

我知道这是迟到,但我想提供一个没有人提供的解决scheme。 该解决scheme允许将文件stream式传输到响应,同时仍允许您修改内容,而无需使用模板引擎或将整个文件caching到内存中。

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

让我先来描述为什么res.sendFile对于那些不知道的人来说是如此的合意。 由于Node是单线程的,因此它通过连续执行很多很多很小的任务来工作 – 这包括从文件系统读取数据并回复一个http请求。 Node没有时间停止它正在做的事情,并从文件系统中读取整个文件。 它会读一点,做别的,多读一点,做别的事情。 回复一个http请求和Node中的大多数其他操作也是一样(除非你明确地使用一个操作的sync版本 – 比如readFileSync – 如果你可以帮忙的话,不要那样做,认真的,不要 – 这是自私的)。

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

 app.use('/index.html', (req, res) => { fs.readFile('../public/index.html', data => { res.send(data); }); }); 

这似乎是正确的,它的工作原理,但效率非常低。 由于我们知道Node以小块进行操作,所以最好的办法是在从文件系统读取数据时将小块数据发送到浏览器。 块不会被存储在内存中,您的服务器现在可以处理更多的stream量。 这个概念被称为stream式传输,这就是res.sendFile所做的事情 – 它将文件从文件系统直接传输给用户,并使内存免受更多重要的影响。 以下是您手动执行的方式:

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

如果您想在对文件稍作修改的情况下继续将文件传输到用户,则此解决scheme适合您。 请注意,这不是对模板引擎的替代,而是应该用于对文件进行stream式处理时进行小的更改。 下面的代码将附加一个小的脚本标签与数据到HTML页面的主体。 它还显示了如何在http响应stream中添加或附加内容:

 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); }); 

那么,这是有点老,但我没有看到任何足够的答案,除了“为什么不”。 你有办法将参数传入静态文件。 这很容易。 考虑下面的代码(使用快递):

  let data = fs.readFileSync('yourPage.html'); if(data) res.send(data.replace('param1Place','uniqueData')); //else - 404 

现在,例如,只需在您的.Page.html中设置一个cookie,如下所示:

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

你可以在你的js中简单地从yourCookieName中提取 uniqueData的内容

您只能从服务器返回一个响应。 最常见的做法是用nunjucks或者jade在服务器上模拟你的文件。 另一种select是在客户端上呈现文件,然后使用javascript对服务器进行ajax调用以获取其他数据。 我想你也可以在cookie中设置一些数据,然后通过javascript读取客户端的数据。

(除非你想模板的HTML文件插入JSON数据到脚本标签)。 你需要暴露一个api端点来expression发送数据到页面,并在页面上有一个函数来访问它。 例如,

 // send the html app.get('/', (req, res) => res.sendFile('index')); // send json data app.get('/data', (req, res) => res.json(data)); 

现在在客户端,您可以创build一个访问此端点的请求

 function get() { return new Promise((resolve, reject) => { var req = new XMLHttpRequest(); req.open('GET', '/data'); req.onload = () => resolve(req.response); }); // then to get the data, call the function get().then((data) => { var parsed = JSON.parse(data); // do something with the data }); 

编辑:

所以箭头function可能不工作客户端。 请务必在实际代码中用函数(){}replace它们