处理连续的JSON数据流

64

这个已经废弃的页面http://stream.twitter.com/1/statuses/sample.json曾经返回一个连续无限的JSON数据流。

我想在自己的网页中使用jQuery(或JavaScript,但最好是jQuery)处理它,以便能够根据Twitter实时动态显示可视化效果。

由于据我所知,jQuery的parseJSON函数仅在服务器发送所有数据后执行回调函数,但这实际上是一个持续的数据流。 我怎样才能在数据“发生时”处理它,同时保持连接运行?


1
jQuery 1.6.2现在支持流处理吗? 我在文档中找不到任何信息。 - chovy
4个回答

82
这种事情现在最好使用WebSockets来完成,根据CanIUse.Com的数据,除了Opera Mini(请查看该链接以获取有关旧版或所有浏览器的更多详细信息,并单击“资源”选项卡以查看更多链接),WebSockets现在在所有主要浏览器中都是可用的。概述来说,WebSockets支持IE 10+、Edge 12+、Firefox 11+(如果在WebWorker上下文中,则为38+)、Chrome 16+、Opera 12.1+、Safari 7+、Android 4.4+和Opera Mobile 12.1+。 注意:您可能还想了解Service Workers和Web Workers,尽管它们具有不同的用例和不同的功能。 它看起来像这样:
var connection = new WebSocket(
   'ws://html5rocks.websocket.org/echo',
   ['soap', 'xmpp']
);

立即将某些事件处理程序附加到连接上,可以让您知道连接何时打开、何时收到传入消息或是否发生错误。

发送消息就变得如此简单:

connection.send('your message');
connection.send(binaryData);

请查看Introducing WebSockets: Bringing Sockets to the Web,了解如何完成此操作的完整说明。

ASP.Net开发人员:如果您需要支持旧版浏览器并且不想自己弄清楚如何处理不支持WebSockets的浏览器,请考虑使用SignalR等库。

旧版浏览器的EventSource API答案

现在大多数浏览器都实现了EventSource API,只要流能够以内容类型text/event-stream传递,就可以轻松地进行长轮询。无法将流工程化为该内容类型的旧版浏览器或那些由于任何原因无法这样做的开发人员可以使用一些helper script来完成相同的操作。

以下是一个示例:

var jsonStream = new EventSource('https://example.com/yourstreamingservice')
jsonStream.onmessage = function (e) {
   var message = JSON.parse(e.data);
   // handle message
};

这基本上是我下面概述的完整版本。

针对非常老的浏览器的甚至更旧的服务流式答案

您需要的是称为长轮询的东西。 您将需要一个自定义的 AJAX onreadystatechange 处理函数。 您将需要定期检查内容,而不是等待整个流完成(因为它永远不会完成)。 请注意,您需要在 IE 9 及以下版本中进行一些重量级处理,使用 iframe

大致如下:

  • 响应每个 onreadystatechange 事件并检查给定流到当前字符的内容,以查看是否有足够的数据来消耗一个或多个离散事件。 您将需要使用 javascript 字符串处理函数自行解析流。 可以使用 split、indexOf、正则表达式、循环等组合来完成此任务。
  • 如果尚未有足够的内容,则退出并等待下一个事件。
  • 我非常确定每次 onreadystatechange 处理程序触发时,responseText 将是到目前为止接收到的所有数据。 定义一个持久变量,它将保存尚未正确处理的第一个字符的位置。
  • 一旦有足够的内容出现在流中以呈现一个或多个离散事件,请逐个将它们取出并将它们传递给您的 JSON 解析器,以将文本实际呈现为对象。 正常使用它们。

查看这个HTTP流式传输要点了解一种资源,或者在SoftwareAs上使用流式传输作为轮询服务器的替代方法。如果您必须支持IE 9或更早版本,则需要使用iframe方法。

这是Ajax设计模式:创建具有编程和可用性模式的Web 2.0站点书中的一句引用

总之,服务流使HTTP流媒体方法更加灵活,因为您可以流传任意内容而不是JavaScript命令,并且可以控制连接的生命周期。但是,它结合了两种在浏览器中不一致的技术,具有可预测的可移植性问题。实验表明,页面流技术确实适用于IE [9及更早版本]和Firefox,但服务流仅适用于Firefox,无论使用XMLHTTPRequest还是IFrame。在第一种情况下,IE [9及更早版本]会抑制响应直到完成,在IFrame中,如果使用解决方法,则可以正常工作:IE [9及更早版本]接受来自服务器的消息,只要发送256个虚拟字节即可,然后发送消息。此后,所有消息都将如预期般到达。因此,在IE [9及更早版本]中也可以进行完整的服务流!

请注意,这是2006年的内容,因此肯定已经过时,但如果您必须支持旧版浏览器,则仍然相关。

安全问题

普通AJAX无法跨域,这意味着(现在我注意到您想从Twitter流)您将无法执行您所要求的操作。这可以通过JSONP解决,但是由于JSONP的本质无法进行服务流,并且Twitter也不提供JSONP。还有跨域资源共享(CORS),但Twitter不会为您设置这个 - 这是他们只会为与他们关联的域名做的事情。而且CORS需要现代浏览器。

你唯一的选择是在你的Web服务器上创建一个代理服务,用它来执行向Twitter发出请求并返回数据。这只能在与主页面相同的域中完成。这样做还可以使用iframe技术创建适用于IE的版本。如果你不关心旧版IE,你可以自己实现CORS以打败域限制,前提是你知道将进行请求的域。
如果你完全控制客户端软件(比如企业内部网络),还有另一种选择:将Web浏览器托管在本地编译的可执行应用程序的用户表单中。我只在C#中使用过这种方法,但我想其他语言也可能会有类似的实现。当你使用正确的浏览器对象时,因为它是托管在C#应用程序中,所以C#应用程序可以打败跨域安全限制,读取和写入所有页面内容,无论它来自什么域。我怀疑你的情况不是这种情况,但我想把这个选项放在这里供其他人参考。

EventSource只能与text/event-stream内容类型一起使用:http://www.html5rocks.com/en/tutorials/eventsource/basics/ - Adam
1
@GabrieleCirulli,你是2048的Gabrielle Cirulli吗?我很荣幸能帮助到你! :) - ErikE
HTTP流媒体链接已失效。 - Tyler
1
@Tyler 谢谢,已修复。如果您发现其他问题,请告诉我! - ErikE

8
我有一个开源项目,可以在现代浏览器上实现此功能(并在旧版浏览器上回退到类似于jQuery的语法)。调用语法类似于jQuery.ajax:

http://oboejs.com


链接失效了,也许在 GitHub 上还能找到?这是吗?https://github.com/jimhigson/oboe.js-website - Max von Hippel

4

您在问题中指定的URL发送JSON响应流。由于浏览器中的跨域安全限制,您无法使用JavaScript访问它。您需要在服务器端实现桥接脚本,可以使用AJAX请求定期轮询或将您的站点托管在Twitter.com上。第一种方法似乎更可行。


我能达到的最小间隔是多少?我需要它非常快。 - kettlepot
@Gabriele Cirulli,你所说的最小间隔是指什么?轮询间隔吗?这将取决于客户端浏览器与服务器之间的网络速度连接以及呈现DOM元素的能力。 - Darin Dimitrov
JSONP可以解决跨域安全问题,但我认为服务流将无法正常工作。 - ErikE
@ErikE,这个 Twitter 流 API 不支持 JSONP。 - Darin Dimitrov
没错,Darin,那就是我想说的。 - ErikE

-14

从根本上讲,网页无法保持与服务器的实时连接。Web浏览器向服务器发送请求,服务器将响应(包括HTML和其他内容)发送回客户端(Web浏览器)。将其视为无状态模型-在请求和响应完成后,不会保持任何连接。

因此,您必须自己处理。您必须从客户端调用额外的定期请求。

一种方法是通过setInterval()函数定期调用您的AJAX / GET功能。例如:

setInterval(function() {

    $.ajax({
      url: "mydata/get",
      success: function(){
        // update content.
      }
    });

}, 5000);

这将每5秒触发一次 AJAX 请求到 mydata/get(或您想使用的任何 URL)。

6
我认为你完全没有理解被问的内容。 - ErikE
我需要数据是实时的,每5秒钟请求一次不起作用,而且请求太多会导致性能极差。 - kettlepot
就像我说的那样,在网页的生命周期中,不存在所谓的“实时”。你只能从页面中获取数据,而无法向页面推送数据。 - Kon
AJAX模式的HTTP Streaming页面似乎认为您可以在Web上进行推送。此外,还可以查看更多关于Comet的内容。 - ErikE
1
你能在回答中详细阐述这些负面影响和风险吗? - ErikE
显示剩余2条评论

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