res. sendfile в Node Express с передачей данных вдоль



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

723   5  

5 ответов:

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

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

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

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

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

Переходите ко дну, если вас не волнует "Почему"

Позвольте мне сначала объяснить, почему res.sendFile так желателен для тех, кто не знает. Поскольку узел является однопоточным, он работает, выполняя много и множество очень маленьких задач подряд - это включает в себя чтение из файловой системы и ответ на запрос http. Ни в какой момент времени Node просто прекращает то, что он делает, и читает всю файловую систему. Он будет читать немного, делать что-то еще, читать еще немного, делать что-то еще. То же самое касается ответа на http - запрос и большинства других операций в узле (если вы явно не используете версию 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);
});

Решение

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

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

Ну, это немного старо, но я не видел никакого достаточного ответа, кроме "почему бы и нет". У вас есть способ передать параметры в статическом файле. И это очень просто. Рассмотрим следующий код на вашем оригинале (с помощью express):

    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>

И вы можете просто вытащить содержимое uniqueData из yourCookieName в любом месте вашего js

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

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

Правка:

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

Comments

    Ничего не найдено.