最安全的javascript JSON内联技术



我使用varnish+esi从RESTFul API返回外部json内容。这种技术使我能够管理请求并刷新数据,而无需为每个请求使用Web服务器资源。

例如:

<head>
.... 
<script> 
 var data = <esi:include src='apiurl/data'>;
</script>
...

包含后,esi清漆将返回:

 var data = {attr:1, attr2:'martin'};

这很好,但如果API返回错误,此技术将生成解析错误。

var data = <html><head><script>...api js here...</script></head><body><h1 ... api html ....

我使用一个隐藏的div来解析并捕获错误,从而解决了这个问题:

...
<b id=esi-data style=display:none;><esi:include src='apiurl/data'></b>
<script>
  try{
    var data = $.parseJSON($('#esi-data').html());
  }catch{ alert('manage the error here');}
....

我也尝试过使用脚本类型text/esi,但浏览器会在脚本标记(wtf)中呈现html,例如:

<script id=esi-data type='text/esi'><esi:include src='apiurl/data'></script>

问题

有什么理由包装标签并避免浏览器解析它吗?

让我扩展一下我在评论中提出的iframe建议——这与你的想法不完全一样!

该方法与您已经在做的几乎完全相同,但您使用的不是像div那样的普通HTML元素,而是iframe

<iframe id="esi-data" src="about:blank"><esi:include src="apiurl/data"></iframe>
var $iframe = $('#esi-data');
try {
    var data = $.parseJSON($iframe.html());
} catch (e) { ... }
$iframe.remove();
#esi-data { display: none; }

这与您的解决方案有何不同?两种方式:

  1. 数据/错误页面对访问者来说是真正隐藏的iframe有一个嵌入的内容模型,这意味着<iframe>…</iframe>标记中的任何内容都会在DOM中被完全替换,但您仍然可以使用innerHTML检索原始内容。

  2. 它是有效的HTML5……有点像在HTML5中,iframe元素内部的标记被视为文本。当然,意味着能够将其解析为片段,并且它只包含短语内容(而不包含script元素!),但它本质上只是被验证器和浏览器视为文本。

  3. 错误页面中的脚本将不会运行内容将被解析为文本,并在DOM中用另一个文档替换——没有机会处理任何script元素。

看看它的实际操作。如果注释掉我删除iframe元素并检查DOM的那一行,就可以确认HTML内容正在被一个空文档替换。还要注意,嵌入的script标记永远不会运行。

重要:如果第三方出于某种原因在其错误页面中添加了iframe元素,则此方法仍可能中断。尽管这可能不太可能,但通过将您的技术与此技术相结合,您可以使该方法更加防弹:用一个隐藏的div包围iframe,当您完成解析时将其删除。

我再尝试一次。

尽管我相信您已经有了最好的解决方案,但我只能想象您使用一种性能相当低的方法来解决这个问题,即在一个单独的HTML窗口中调用esi:insert,然后像在服务器上使用AJAX一样检索内容。也许与此类似?然后检查您检索到的内容,也许可以使用json_decode,并在成功时生成一个错误JSON字符串。

我看到的最大缺点是,我认为这将非常耗时,甚至很可能会延迟您的请求,因为单独的页面被调用,就像您的服务器本身是一个客户端一样,被解析,然后被发送回来。

老实说,我会坚持你目前的解决方案。

这是一个相当棘手的问题,没有真正优雅的解决方案,如果不是根本没有解决方案的话

我问您它是HTML(5)还是XHTML(5)文档,因为在后面的情况下,可以使用CDATA部分来包装内容,将您的解决方案稍微更改为以下内容:

...
<b id='esi-data' style='display:none;'>
    <![CDATA[ <esi:include src='apiurl/data'> ]]>
</b>
<script>
    try{
        var data = $.parseJSON($('#esi-data').html());
    }catch{ alert('manage the error here');}
....

当然,这个解决方案如果有效:

  1. 您使用的是XHTML5
  2. 该错误不包含CDATA节(因为CDATA节嵌套是不可能的)

我不知道从一个序列化切换到另一个是否是一种选择,但我想澄清我的问题的意图。希望它能帮助你:)。

您不能简单地更改API以在出现错误时返回JSON { "error":"error_code_or_text" }吗?若你们这样做的话,你们甚至可以在你们的界面上做一些有意义的事情来提醒用户错误。

<script>var data = 999;</script>
<script>
data = <esi:include src='apiurl/data'>;
</script>
<script>
if(data == 999) alert("there was an error");
</script>

如果出现错误并且"数据"不是JSON,那么将抛出javascript错误。下一个脚本块将处理这个问题。

最新更新