处理连续的 JSON 流

IT技术 javascript jquery json stream
2021-03-13 13:17:50

(现已不存在的)页面http://stream.twitter.com/1/statuses/sample.json用于返回连续和无休止的 JSON 数据流。

我想在我自己的网页中使用 jQuery(或 JavaScript,但最好是 jQuery)来处理它,以便能够根据推文的实时提要显示视觉效果。

因为据我所知 jQueryparseJSON函数只会在服务器发送完所有数据后才会执行回调函数,但这实际上是一个连续的数据流。我怎样才能“在发生时”处理数据但仍然保持连接运行?

4个回答

这种事情现在最好使用WebSockets来完成,根据 CanIUse.Com 的说法,它除 Opera Mini 之外的所有主要浏览器中都可用(有关旧浏览器或所有浏览器的更多详细信息,请参阅该链接,并单击“资源”选项卡以查看更多链接) . 作为概述,IE 10+、Firefox 11+(如果在 WebWorker 上下文中为 38+)、Chrome 16+、Opera 12.1+、Safari 7+、Android 4.4+、Opera Mobile 12.1+ 支持 websocket。

注意:您可能还想了解Service Workers 和 Web Workers,尽管它们有不同的用例和不同的能力。

它看起来像这样:

var connection = new WebSocket(
   'ws://html5rocks.websocket.org/echo',
   ['soap', 'xmpp']
);

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

发送消息变得如此简单:

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

有关如何执行此操作的完整说明,请参阅WebSockets 简介:将 Sockets 引入 Web

ASP.Net 开发人员:如果出于某种原因您需要支持旧浏览器并且不想自己弄清楚如何处理那些不支持 WebSockets 的浏览器,请考虑使用诸如SignalR 之类的库

旧版浏览器的旧 EventSource API 答案

大多数浏览器现在都实现了EventSource API,这使得长轮询变得非常容易,只要流可以使用 content-type 传送text/event-stream较旧的浏览器或那些出于任何原因无法设计流以具有该内容类型的开发人员可以使用一些帮助脚本来做同样的事情。

下面是一个例子:

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

这基本上是我在下面概述的确切内容的完整版本。

对于非常老的浏览器,更旧的服务流媒体答案

你想要的是长轮询。您需要一个自定义的 AJAXonreadystatechange处理函数。您无需等待整个流完成(因为它永远不会完成),而是需要定期检查内容。请注意,您需要做一些繁重的工作才能在 IE 9 及更低版本中使用iframe.

大致:

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

查看此HTTP Streaming gist了解一种资源,或将Streaming 作为在 SoftwareAs轮询服务器的替代方法如果您必须支持 IE 9 或更早版本,则需要使用该iframe方法。

以下引用自Ajax 设计模式:使用编程和可用性模式创建 Web 2.0 站点》一书

总之,Service Streaming 使 HTTP Streaming 方法更加灵活,因为您可以流式传输任意内容而不是 Javascript 命令,并且因为您可以控制连接的生命周期。但是,它结合了两种跨浏览器不一致的技术,具有可预测的可移植性问题。实验表明,Page Streaming 技术在 IE [9 及更早版本] 和 Firefox 上都有效,但 Service Streaming 仅适用于 Firefox,无论是使用 XMLHTTPRequest 还是 IFrame。在第一种情况下,IE [9 及更早版本] 会抑制响应直到其完成,如果使用变通方法,则 IFrame 可以工作:IE [9 及更早版本] 在前 256 个字节后接受来自服务器的消息,因此唯一的事情要做的是在发送消息之前发送 256 个虚拟字节。在此之后,所有消息都将按预期到达。

请注意,它是从 2006 年开始的,所以它肯定已经过时了,但是如果您必须支持旧浏览器,它仍然是相关的。

安全问题

普通的 AJAX 不能跨域,这意味着(现在我注意到你想从 twitter 流式传输的事实)你将无法做你所要求的。这可以通过 JSONP 解决,但 JSONP 本质上不能进行服务流式传输,而且无论如何 twitter 也不提供。还有跨域资源共享(CORS),但 twitter 不会为你设置——这是他们只为附属域做的事情。而且 CORS 需要现代浏览器。

因此,您唯一的选择是在您的 Web 服务器上创建一个代理服务,为您执行对 twitter 的请求,然后分发数据。这只能从与提供主页的同一域中完成。这样做还允许您使用 iframe 技术创建一个适用于 IE 的版本。如果您不关心旧的 IE 版本,如果您知道将发出请求的域,您可以自己实现 CORS 来克服域限制。

如果您可以完全控制客户端软件(就像这是用于公司内部网),还有另一种选择:将 Web 浏览器托管在已编译的本地执行应用程序的用户表单中。我只使用 C# 做到了这一点,但我想其他语言也可以做到这一点。当您使用正确的浏览器对象时,因为它托管在 C# 应用程序中,C# 应用程序可以克服跨域安全限制,读取和写入所有页面内容,无论它来自哪个域。我怀疑你的情况是这样的,但我想把这个选项放在这里,供其他可能欣赏它的人使用。

EventSource 仅适用于text/event-stream内容类型:html5rocks.com/en/tutorials/eventsource/basics
2021-04-26 13:17:50
HTTP Streaming 链接已失效。
2021-05-01 13:17:50
@Tyler 谢谢,已修复。如果您发现任何其他问题,请告诉我!
2021-05-06 13:17:50
@GabrieleCirulli 你是2048 年成名的 Gabrielle Cirulli吗?很荣幸能帮到你!:)
2021-05-10 13:17:50

我有一个开源项目,它允许在现代浏览器上执行此操作(并在旧浏览器上回退到 jQuery 样式)。调用语法类似于 jQuery.ajax:

http://oboejs.com

链接已损坏,也许还在 GitHub 上的某个地方?是这个吗? github.com/jimhigson/oboe.js-website
2021-05-20 13:17:50

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

@ErikE,这个 twitter 流 API 不支持 JSONP。
2021-04-24 13:17:50
没错,达林,这就是我的意思。
2021-04-25 13:17:50
我可以达到的最小间隔是多少?我需要它非常快。
2021-05-07 13:17:50
JSONP 可以解决跨域安全问题,但我认为服务流将无法正常工作。
2021-05-15 13:17:50
@Gabriele Cirulli,你说的最小间隔是多少?轮询间隔?这将取决于您的客户端浏览器与服务器的网络速度连接以及渲染 DOM 元素的能力。
2021-05-19 13:17:50

一个非常基础级别的网页无法保持与服务器的实时/运行连接。Web 浏览器向服务器发送请求。服务器将响应(HTML 等)发送回客户端(Web 浏览器)。将此视为无状态模型 - 在请求和响应完成后,没有任何连接保持活动状态。

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

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

setInterval(function() {

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

}, 5000);

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

我认为你已经完全错过了被问到的问题。
2021-04-30 13:17:50
@ErikE,那你为什么不解释一下?
2021-05-03 13:17:50
您会在回答中详细说明这些不利影响和风险吗?
2021-05-10 13:17:50
就像我说的,在网页的生命中没有“活”这样的东西。您只能从页面中提取数据,不能推送到页面上。
2021-05-14 13:17:50
我需要数据是实时的,每 5 秒执行一次请求是行不通的,而做太多只会工作得非常糟糕
2021-05-15 13:17:50