在Node/Express+EJS中向客户端传递对象?

39

我有一个相当大的对象需要传递给客户端脚本的函数。我已经尝试使用JSON.stringify,但是遇到了一些性能相关的问题。在ejs中是否有可能做到这样的事情?

app.get('/load', function(req, res) {
    var data = {
        layout:'interview/load',
        locals: {
            interview: '',
            data: someLargeObj
        }
    };
    res.render('load', data);
});

在我的客户端脚本中,我会像这样将这个对象传递给一个函数

<script type="text/javascript">
    load(<%- data %>); // load is a function in a client script
</script>

当我尝试这样做时,我会得到以下两种情况之一:

<script type="text/javascript">
    load();
</script>
或者
<script type="text/javascript">
    load([Object object]);
</script>

JSON.stringify 是唯一的方法。 - Florian Margaine
@FlorianMargaine,请问为什么要在客户端使用'JSON.stringify()'?因为Node会将数据作为对象传递,而stringify只是将其转换为字符串,我们需要一个对象对吧?如果没有JSON.stringify(),它就无法正常工作。 - Vishal-L
@Vishal-Lia — 在 EJS 代码中,你应该使用 JSON.stringify 服务端,而不是在传递给浏览器的 <script> 数据中使用客户端。 - Quentin
@Vishal-Lia,你找到你问题的答案了吗?下面的回答都没有告诉我们为什么在实例中传递数据作为对象时必须使用JSON.stringify。此外,为什么JSON.stringify将其转换为对象,而它应该做相反的操作呢? - jedu
5个回答

91

在Node.js中:

res.render('mytemplate', {data: myobject});

在EJS中:

<script type='text/javascript'>
  var rows =<%-JSON.stringify(data)%>
</script>

安全注意事项:不要使用此方法来呈现用户提供的数据对象。否则像小博比·泰布尔斯(Little Bobby Tables)这样的人可能会包含一个子字符串,破坏JSON字符串并启动可执行标记等等。例如,在Node.js中看起来很无害...

var data = {"color": client.favorite_color}

但如果用户输入了像这样的颜色,可能会导致客户端提供的脚本在用户浏览器中执行:

"titanium </script><script>alert('pwnd!')</script> oxide"

如果您需要包含用户提供的内容,请参阅https://dev59.com/YWQo5IYBdhLWcg3wXuin#37920555,使用Base64编码可以得到更好的答案。


4
你能告诉我 <%-<%= 之间的区别吗?为什么结尾没有加上 ; 呢? - gr3g
16
<%= x %> 插值直接输出 x 的值,而 <%-x%> 则将其进行 HTML 转义,这样像 <> 这样的字符就不会被 HTML 解析器误认为是标签。 - prototype
1
在Javascript终端中,分号是可选的,但最好还是包含它们。 - prototype
2
@Vishal-Lia Node具有实时对象,但HTML页面是文本。如果您不使用stringify,则该对象将呈现为“[Object]”。使用stringify允许HTML页面将对象表示为浏览器可以解析回实时对象的内容。 - prototype
1
哦,我真希望昨晚看到这个答案。我差点把电脑扔出窗外了。谢谢你。 - Ryan
显示剩余6条评论

15

这是预期的行为。您的模板引擎正在尝试从对象中创建一个字符串,导致出现 "[Object object]"。如果您真的想以这种方式传递数据,我认为通过将对象转换为字符串来执行正确操作。


2
JSON.stringify(someLargeObj) - alessioalex

5

如果你正在使用模板技术,那么最好在模板中获取值,例如用户是否已登录。你可以使用以下方式获取发送本地数据:

<script>
    window.user = <%- JSON.stringify(user || null) %>
</script>

从服务器端代码发送用户数据。

res.render('profile', {
    user: user.loggedin,
    title: "Title of page"
});

1

当向ejs传递对象时,有更好的方法,您不必处理JSON.stringfy和JSON.parse方法,这些方法有点棘手和令人困惑。相反,您可以使用for-in循环遍历对象的键,例如:

如果您有一个像此类层次结构的对象

{
    "index": {
        "url": "/",
        "path_to_layout": "views/index.ejs",
        "path_to_data": [
            "data/global.json",
            {
                "data/meta.json": "default"
            }
        ]
    },
    "home": {
        "url": "/home",
        "path_to_layout": "views/home/index.ejs",
        "path_to_data": [
            "data/global.json",
            {
                "data/meta.json": "home"
            }
        ]
    },
    "about": {
        "url": "/about",
        "path_to_layout": "views/default.ejs",
        "path_to_data": [
            "data/global.json",
            {
                "data/meta.json": "about"
            }
        ]
    }
}

在EJS中,您可以像这样循环yourObject;
<% if ( locals.yourObject) { %>
  <% for(key in yourObject) { %>
    <% if(yourObject.hasOwnProperty(key)) { %>
      <div> <a class="pagelist" href="<%= yourObject[key]['subkey'] %>"><%= key %></a></div>
    <% } %>
  <% } %>
<% } %>

对于这个例子,[key] 可以取 'index'、'home' 和 'about' 值,而 subkey 可以是它的任何一个子元素,例如 'url'、'path_to_layout'、'path_to_data'。

-2
你现在得到的结果是这样的:[{'re': 'tg'}]。
实际上,你需要循环它。请参考JavaScript while循环https://www.w3schools.com/js/js_loop_while.asp
然后,在前端使用ejs渲染它...我无法帮忙,因为我使用hbs。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接