Express - 在单个请求中将页面和自定义数据发送到浏览器?

khe*_*hex 15 html javascript http node.js express

如何同时呈现页面并将我的自定义数据传输到浏览器.据我所知,它需要发送两层:第一层是模板,第二层是JSON数据.我想通过骨干来处理这些数据.

正如我从教程中理解expressbb 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}); 
};
Run Code Online (Sandbox Code Playgroud)

我应该如何在页面上捕获这个变量document.card

Che*_*hev 10

我创建了自己的小中间件函数,它添加了一个调用renderWithDatares对象的辅助方法.

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();
});
Run Code Online (Sandbox Code Playgroud)

它接收视图名称,视图模型以及要发送到浏览器的自定义数据.它调用res.render但传递回调函数.这指示express将编译的视图标记作为字符串传递给回调,而不是立即将其传递给响应.一旦我有了视图字符串,我将它添加到数据对象中data.view.然后我使用res.json编译视图将数据对象发送到浏览器:)

编辑:

上面提到的一个警告是,请求需要使用javascript进行,因此它不能是完整页面请求.您需要一个初始请求来下拉包含将发出ajax请求的javascript的主页面.

这非常适合在用户通过AJAX导航到新页面时尝试更改浏览器URL和标题的情况.您可以将新页面的部分视图与页面标题的一些数据一起发送回浏览器.然后,您的客户端脚本可以将部分视图放在页面上,更新页面标题栏,并在需要时更新URL.

如果您想要将完整的HTML文档与一些初始JavaScript数据一起发送到浏览器,那么您需要将该JavaScript代码编译到视图本身中.绝对有可能做到这一点,但我从来没有找到一种不涉及一些字符串魔法的方法.

例如:

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

// someView.jade
script.
    var someData = !{data};
Run Code Online (Sandbox Code Playgroud)

注意:!{data}使用而不是#{data}因为jade默认转义HTML会将所有引号转换为"占位符.

起初看起来真的很奇怪,但它确实有效.基本上,您在服务器上获取JS对象,将其转换为字符串,将该字符串呈现在已编译的视图中,然后将其发送到浏览器.当文档最终到达浏览器时,它应该如下所示:

// someSite.com/someView
<script type="text/javascript">
    var someData = { "message": "hi" };
</script>
Run Code Online (Sandbox Code Playgroud)

希望这是有道理的.如果我要重新创建我的原始帮助方法来缓解第二种情况的痛苦,那么它看起来像这样:

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

所有这一切都是获取您的自定义数据对象,为您进行字符串化,将其添加到视图的模型,然后正常呈现视图.现在你可以打电话res.renderWithData('someView', {}, { message: 'hi' });; 您只需要确保视图中的某个位置可以获取该数据字符串并将其呈现为变量赋值语句.

html
    head
        title Some Page
        script.
            var data = !{data};
Run Code Online (Sandbox Code Playgroud)

不会撒谎,这整个事情都有点粗暴,但是如果它能为你节省额外的服务器之旅,那就是你所追求的那样,那就是你需要做的事情.也许有人可以想到一些更聪明的东西,但我只是看不出你将如何获得数据已经存在于第一次呈现的完整HTML文档中.

EDIT2:

这是一个工作示例:https://c9.io/chevex/test

您需要拥有(免费)Cloud9帐户才能运行该项目.登录,打开app.js,然后单击顶部的绿色运行按钮.


Dan*_*ina 5

我的方法是发送包含信息的cookie,然后从客户端使用它。

server.js

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

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

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
  }
Run Code Online (Sandbox Code Playgroud)


演练

从服务器,您在呈现页面之前发送cookie,因此在加载页面时cookie可用。

然后,从客户端获取包含我在此处找到的解决方案的cookie并将其删除。Cookie的内容存储在我们的常量中。如果cookie存在,则将其解析为对象并使用它。请注意,parseObjectFromCookie您必须首先在内部解码内容,然后将JSON解析为一个对象。

注意事项

  • 如果要异步获取数据,请呈现之前小心发送cookie 。否则,您将收到错误消息,因为res.render()响应结束。如果数据获取花费的时间太长,则可以使用另一种解决方案,该解决方案的保存时间不会太长。一种替代方法是从客户端打开套接字,然后发送您在服务器中持有的信息。有关此方法,请参见此处

  • 可能data不是cookie的最佳名称,因为您可能会覆盖某些内容。使用对您的目的更有意义的东西。

  • 我在其他任何地方都找不到此解决方案。我不知道是否由于某些我不知道的原因不建议使用cookie。我只是认为它可以工作并检查了它,但是我还没有在生产中使用它。

  • 请注意,此方法最大为[4Kbytes](/sf/ask/44865691/),因此它不会不能为所有目的工作。 (2认同)