it-roy-ru.com

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

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

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

  1. res.render отправить страницу в браузер
  2. когда document.ready вызывает jQuery.get для app.get('/post') 
  3. 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?

15
khex

Я создал свою собственную небольшую функцию промежуточного программного обеспечения, которая добавляет вспомогательный метод с именем 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 для отправки объекта данных в браузер вместе с скомпилированным представлением :)

Правка:

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

Это отлично подходит для ситуаций, когда вы пытаетесь изменить URL и заголовок браузера, когда пользователь переходит на новую страницу через AJAX. Вы можете отправить частичный вид новой страницы обратно в браузер вместе с некоторыми данными для заголовка страницы. Затем ваш клиентский сценарий может поместить частичное представление на страницу, где он принадлежит, обновить строку заголовка страницы и, при необходимости, обновить 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, что превращает все кавычки в " заполнители.

Сначала это выглядит ДЕЙСТВИТЕЛЬНО странным, но это работает. По сути, вы берете объект 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 и нажмите зеленую кнопку запуска вверху.

9
Chev

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

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
  }


Прохождение

С сервера вы отправляете куки-файл перед рендерингом страницы, поэтому куки-файл доступен при загрузке страницы.

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

Заметки:

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

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

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

4
Daniel Reina

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

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

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

Проверьте Steamer, крошечный модуль, созданный для этой цели.

https://github.com/rotundasoftware/steamer

2
Brave Dave

Самый элегантный и простой способ сделать это - использовать движок рендеринга (по крайней мере, для этой страницы). Например, используйте движок ejs

node install ejs -s

На сервере.js:

let ejs = require('ejs');    
app.set('view engine', 'ejs');

затем переименуйте нужную страницу index.html в index.ejs и переместите ее в каталог/views. После этого вы можете создать конечную точку API для этой страницы (с помощью модуля mysql):

app.get('/index/:id', function(req, res) { 
    db.query("SELECT * FROM products WHERE id = ?", [req.params.id], (error, results) => {
    if (error) throw error;
        res.render('index', { title: results[0] }); 
    });
});  

Во внешнем интерфейсе вам нужно будет сделать запрос GET, например, с Axios или напрямую, щелкнув ссылку на странице шаблона index.ejs, которая отправляет запрос:

<a v-bind:href="'/index/' + co.id">Click</a>

где co.id - значение параметра данных Vue 'co', которое вы хотите отправить вместе с запросом

0
Danny