2

我正在使用varnish+esi从 RESTFul API返回外部json内容。这种技术允许我管理请求和刷新数据,而无需为每个请求使用网络服务器资源。

例如:

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

包含 esi varnish 后将返回:

 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>

问题

为什么要包装标签并避免浏览器解析它?

4

5 回答 5

4

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

该方法与您已经在做的几乎完全相同,但不是使用像 a 这样的普通 HTML 元素div,而是使用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. 数据/错误页面对您的访问者是真正隐藏的。Aniframe有一个嵌入的内容模型,这意味着<iframe>…&lt;/iframe>标签中的任何内容都会在 DOM 中完全替换——但您仍然可以使用innerHTML.

  2. 它是有效的 HTML5... 之类的。在 HTML5 中,iframe 元素内的标记被视为 text。当然,您应该能够将其解析为片段,并且它仅包含短语内容(并且没有script元素!),但它本质上只是被验证器和浏览器视为文本。

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

看看它的实际效果。如果您注释掉我删除iframe元素的行并检查 DOM,您可以确认 HTML 内容正在被空文档替换。另请注意,嵌入式script标签永远不会运行。

Important: this approach could still break if the third party added an iframe element into their error page for some reason. Unlikely as this may be, you can bulletproof the approach a little more by combining your technique with this one: surround the iframe with a hidden div that you remove when you're finished parsing.

于 2012-08-09T16:47:44.907 回答
1

在这里,我进行了另一次尝试。

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

我认为最大的缺点是我相信这会非常消耗,甚至很可能会延迟您的请求,因为单独的页面被调用,就好像您的服务器自己是客户端一样,被解析,然后发回。

老实说,我会坚持您当前的解决方案。

于 2012-08-02T16:19:40.033 回答
1

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

我问你它是 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 部分嵌套是不可能的)。

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

于 2012-08-08T16:36:09.503 回答
0

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

于 2012-08-02T21:10:18.037 回答
0
<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 错误。下一个脚本块将选择它。

于 2012-08-07T11:27:25.260 回答