Экспресс - отправить страницу и пользовательские данные в браузер по одному запросу?

Как одновременно отображать страницу и передавать свои пользовательские данные в браузер. Поскольку я понял, что ему нужно отправить два слоя: сначала с шаблоном, а затем с данными JSON. Я хочу обрабатывать эти данные по магистрали.

Как я понял из учебников express и bb app, взаимодействуют следующим образом:

  • res.render отправить страницу в браузер
  • когда document.ready запускает jQuery.get до app.get('/post')
  • app.get('/post', post.allPosts) отправить данные на страницу

Это три шага и как сделать это одним?

var visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

exports.index = function(req, res, next){
  res.render('index');
  res.send({data: visitCard}); 
};

И как я должен поймать эту переменную на странице document.card?

Ответы

Ответ 1

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

app.use(function (req, res, next) {
    res.renderWithData = function (view, model, data) {
        res.render(view, model, function (err, viewString) {
            data.view = viewString;
            res.json(data);
        }); 
    };
    next();
});

Требуется имя вида, модель для представления и пользовательские данные, которые вы хотите отправить в браузер. Он вызывает res.render, но передает функцию обратного вызова. Это дает команду express передать скомпилированную разметку вида на обратный вызов в виде строки, а не сразу же передать ее в ответ. Как только у меня есть строка представления, я добавляю его в объект данных как data.view. Затем я использую res.json для отправки объекта данных в браузер в комплекте с скомпилированным представлением:)

Edit:

Одно из предостережений с вышеизложенным заключается в том, что запрос должен быть сделан с помощью javascript, поэтому он не может быть полным запросом страницы. Вам нужен первоначальный запрос, чтобы вытащить главную страницу, содержащую javascript, который сделает запрос ajax.

Это отлично подходит для ситуаций, когда вы пытаетесь изменить URL-адрес и заголовок браузера, когда пользователь переходит на новую страницу через AJAX. Вы можете отправить частичный просмотр новой страницы обратно в браузер вместе с некоторыми данными для названия страницы. Тогда ваша клиентская сторона script может поместить частичный вид там, где он принадлежит на странице, обновить строку заголовка страницы и, при необходимости, обновить URL.

Если вы хотите отправить полностью полный HTML-документ в браузер вместе с некоторыми исходными данными JavaScript, вам необходимо скомпилировать этот код JavaScript в самом представлении. Это определенно возможно сделать, но я никогда не нашел способ, который не связан с некоторой магией строк.

Например:

// controller.js
var someData = { message: 'hi' };
res.render('someView', { data: JSON.stringify(someData) });

// someView.jade
script.
    var someData = !{data};

Примечание: !{data} используется вместо #{data}, потому что jade экранирует HTML по умолчанию, который превратит все кавычки в " placeholders.

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

// someSite.com/someView
<script type="text/javascript">
    var someData = { "message": "hi" };
</script>

Надеюсь, это имеет смысл. Если бы я должен был воссоздать свой оригинальный вспомогательный метод, чтобы облегчить боль этого второго сценария, тогда он будет выглядеть примерно так:

app.use(function (req, res, next) {
    res.renderWithData = function (view, model, data) {
        model.data = JSON.stringify(data);
        res.render(view, model);
    };
    next();
});

Все это - это взять свой пользовательский объект данных, подкрепить его для вас, добавить его в модель для представления, а затем отобразить представление как обычно. Теперь вы можете позвонить res.renderWithData('someView', {}, { message: 'hi' });; вам просто нужно убедиться, что где-то в вашем представлении вы захватите эту строку данных и превратите ее в оператор присваивания переменных.

html
    head
        title Some Page
        script.
            var data = !{data};

Не ложь, все это выглядит грубо, но если это избавит вас от дополнительной поездки на сервер и того, что вы после этого сделаете, как вам это нужно. Может быть, кто-то может подумать о чем-то более умном, но я просто не понимаю, как еще вы получите данные, которые уже присутствуют в полном HTML-документе, который отображается впервые.

Edit2:

Вот рабочий пример: https://c9.io/chevex/test

Для запуска проекта вам необходимо иметь (бесплатную) Cloud9-учетную запись. Войдите в систему, откройте приложение app.js и нажмите зеленую кнопку запуска вверху.

Ответ 2

Мой подход заключается в том, чтобы отправить файл cookie с информацией, а затем использовать его с клиентом.

server.js

const visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

router.get('/route', (req, res) => {
  res.cookie('data', JSON.stringify(pollsObj));
  res.render('index');
});

client.js

const getCookie = (name) => {
  const value = "; " + document.cookie;
  const parts = value.split("; " + name + "=");
  if (parts.length === 2) return parts.pop().split(";").shift();
};

const deleteCookie = (name) => {
  document.cookie = name + '=; max-age=0;';
};

const parseObjectFromCookie = (cookie) => {
  const decodedCookie = decodeURIComponent(cookie);
  return JSON.parse(decodedCookie);
};

window.onload = () => {
  let dataCookie = getCookie('data');
  deleteCookie('data');

  if (dataCookie) {
    const data = parseObjectFromCookie(dataCookie);
    // work with data. `data` is equal to `visitCard` from the server

  } else {
    // handle data not found
  }


Walkthrough

От сервера вы отправляете cookie перед отображением страницы, поэтому cookie доступен, когда страница загружается.

Затем от клиента вы получите файл cookie с найденным мной решением и удалите его. Содержимое cookie хранится в нашей константе. Если файл cookie существует, вы анализируете его как объект и используете его. Обратите внимание, что внутри parseObjectFromCookie вам сначала нужно декодировать контент, а затем разобрать JSON на объект.

Примечания

  • Если вы получаете данные асинхронно, будьте осторожны, чтобы отправить рендеринг cookie до. В противном случае вы получите сообщение об ошибке, потому что res.render() завершает ответ. Если выборка данных занимает слишком много времени, вы можете использовать другое решение, которое долго не удерживает рендеринг. Альтернативой может быть открытие сокета с клиента и отправка информации, которую вы содержали на сервере. См. здесь для этого подхода.

  • Вероятно, data не лучшее имя для файла cookie, так как вы могли бы перезаписать что-то. Используйте что-то более значимое для своей цели.

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

Ответ 3

Используйте res.send вместо res.render. Он принимает исходные данные в любой форме: строку, массив, простой старый объект и т.д. Если это объект или массив объектов, он будет сериализовать его для JSON для вас.

var visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

exports.index = function(req, res, next){
  res.send(visitCard}; 
};