Res.sendfile в Node Экспресс с передачей данных вдоль

Есть ли способ перенаправить файл HTML из приложения Node.JS с чем-то вроде: res.sendFile выражения и передавать данные JSON вместе с html файлом?

Ответ 1

Вы получаете один ответ от данного запроса. Вы можете объединить несколько вещей в один ответ или потребовать от клиента сделать отдельные запросы для получения отдельных вещей.

Если то, что вы пытаетесь сделать, - это взять файл HTML и изменить его, вставив в него некоторый JSON, тогда вы не можете использовать только res.sendFile(), потому что это просто читает файл с диска или кеша и напрямую передает потоки это как ответ, не предлагая изменить его.

Более распространенный способ сделать это - использовать систему шаблонов, которая позволяет вставлять вещи в HTML файл (обычно заменяя специальные теги вашими собственными данными). Существует буквально сотни шаблонных систем и многие из них поддерживают node.js. Общий выбор для node.js - это Jade, Handlebars, Ember, Dust, EJS, Mustache.

Или, если вы действительно этого хотели, вы можете прочитать файл HTML в памяти, использовать для него какую-то операцию .replace(), чтобы вставить ваши собственные данные, а затем res.send() полученный измененный файл.

Ответ 2

Я знаю, что это поздно, но я хотел предложить решение, которое никто другой не предоставил. Это решение позволяет передавать поток в ответ, сохраняя при этом возможность изменять содержимое без необходимости использования механизма шаблонов или буферизации всего файла в памяти.

Продвигайтесь вниз, если вас не волнует "почему"

Позвольте мне сначала описать, почему 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 делает вещи в небольших кусках, лучше всего будет отправить небольшие куски данных в браузер, поскольку они считываются из файловой системы. Куски никогда не хранятся в памяти, и ваш сервер теперь может обрабатывать на порядок больше трафика. Эта концепция называется потоковой передачей, и это то, что делает res.sendFile - она ​​передает файл непосредственно пользователю из файловой системы и освобождает память для более важных вещей. Вот как это выглядит, если вы должны сделать это вручную:

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

Решение

Если вы хотите продолжить передачу файла пользователю, внося небольшие изменения в него, то это решение для вас. Обратите внимание, что это не замена механизма шаблонов, а скорее используется для внесения небольших изменений в файл по мере его потоковой передачи. В приведенном ниже коде будет добавлен небольшой тег script с данными в тело 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);
});

Ответ 3

У вас есть только один ответ, который вы можете вернуть с сервера. Наиболее распространенная задача - создать шаблон своего файла на сервере с nunjucks или jade. Другим вариантом является рендеринг файла на клиенте, а затем использование javascript для вызова ajax на сервер для получения дополнительных данных. Я полагаю, вы также можете установить некоторые данные в файл cookie, а затем прочитать это на стороне клиента через javascript.

Ответ 4

Хорошо, это было немного старым, но я не видел достаточного ответа, кроме "почему бы и нет". У вас есть способ передать параметры IN static file. И это довольно легко. Рассмотрите следующий код по вашему происхождению (с помощью экспресс):

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

Теперь, например, просто установите cookie в файле yourPage.html, например:

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

И вы можете явно вытащить содержимое уникальных данных из вашегоCookieName, где бы вы ни хотели, в js

Ответ 5

(Если вы не хотите, чтобы шаблон html файла вставлял json-данные в тег script). Вам нужно будет выставить конечную точку api, чтобы выразить отправку по данным на страницу, и иметь функцию на странице для доступа к ней. например,

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

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

Теперь на стороне клиента вы можете создать запрос для доступа к этой конечной точке

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

EDIT:

Таким образом, функции стрелок, вероятно, пока не работают на стороне клиента. обязательно замените их функцией() {} в вашем реальном коде