facebook、gmail如何发送实时通知?

发布于 2024-07-26 03:20:12 字数 622 浏览 2 评论 0 原文

我读过一些关于这个主题的帖子,答案是 comet、反向 ajax、http 流、服务器推送等。

Gmail 上的传入邮件通知如何工作?

GMail Chat 如何在没有客户端交互的情况下发出 AJAX 请求?

我想知道是否有任何代码参考可以让我编写一个非常简单的例子。 许多帖子或网站只是谈论该技术。 很难找到完整的示例代码。 另外,似乎有很多方法可以用来实现comet,例如Hidden IFrame、XMLHttpRequest。 在我看来,使用 XMLHttpRequest 是更好的选择。 您如何看待不同方法的优缺点? Gmail 使用哪一款?

我知道它需要在服务器端和客户端都执行此操作。 有 PHP 和 Javascript 示例代码吗?

I have read some posts about this topic and the answers are comet, reverse ajax, http streaming, server push, etc.

How does incoming mail notification on Gmail works?

How is GMail Chat able to make AJAX requests without client interaction?

I would like to know if there are any code references that I can follow to write a very simple example. Many posts or websites just talk about the technology. It is hard to find a complete sample code. Also, it seems many methods can be used to implement the comet, e.g. Hidden IFrame, XMLHttpRequest. In my opinion, using XMLHttpRequest is a better choice. What do you think of the pros and cons of different methods? Which one does Gmail use?

I know it needs to do it both in server side and client side.
Is there any PHP and Javascript sample code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

A君 2024-08-02 03:20:12

Facebook 的做法非常有趣。

执行此类通知的常见方法是按照给定的时间间隔(可能每隔几秒)轮询服务器上的脚本(使用 AJAX),以检查是否发生了某些情况。 然而,这可能是相当网络密集的,并且您经常发出毫无意义的请求,因为什么也没有发生。

Facebook 的做法是使用彗星方法,而不是按一定时间间隔进行轮询,一旦一项轮询完成,它就会发布另一项轮询。 但是,对服务器上脚本的每个请求都有极长的超时时间,并且服务器只有在发生某些情况时才会响应请求。 如果您在 Facebook 上打开 Firebug 的“控制台”选项卡,您就会看到这种情况的发生,其中对脚本的请求可能需要几分钟的时间。 这确实非常巧妙,因为这种方法立即减少了请求的数量以及发送请求的频率。 您现在实际上拥有了一个允许服务器“触发”事件的事件框架。

在这背后,就这些民意调查返回的实际内容而言,它是一个 JSON 响应,其中似乎是事件列表以及有关事件的信息。 虽然它被缩小了,所以阅读起来有点困难。

就实际技术而言,AJAX 是可行的方法,因为您可以控制请求超时和许多其他事情。 我建议(这里是堆栈溢出陈词滥调)使用 jQuery 来执行 AJAX,它将消除很多交叉兼容性问题。 就 PHP 而言,您可以简单地在 PHP 脚本中轮询事件日志数据库表,并且仅在发生某些情况时才返回客户端? 我预计有很多方法可以实现这一点。

实现:

服务器端:

PHP 中似乎有一些 Comet 库的实现,但说实话,它确实非常简单,可能类似于以下伪代码:

while(!has_event_happened()) {
   sleep(5);
}

echo json_encode(get_events());
  • has_event_happened 函数将只需检查事件表中是否发生了任何事情或其他事情,然后 get_events 函数将返回表中新行的列表? 实际上取决于问题的上下文。

  • 不要忘记更改你的 PHP 最大执行时间,否则它会提前超时!

    不要

客户端:

看一下用于进行 Comet 交互的 jQuery 插件:

也就是说,该插件似乎增加了相当多的复杂性,它在客户端上确实非常简单,也许(使用 jQuery)类似于:

function doPoll() {
   $.get("events.php", {}, function(result) {
      $.each(result.events, function(event) { //iterate over the events
          //do something with your event
      });
      doPoll(); 
      //this effectively causes the poll to run again as
      //soon as the response comes back
   }, 'json'); 
}

$(document).ready(function() {
    $.ajaxSetup({
       timeout: 1000*60//set a global AJAX timeout of a minute
    });
    doPoll(); // do the first poll
});

整个事情在很大程度上取决于您现有的架构是如何组合在一起的。

The way Facebook does this is pretty interesting.

A common method of doing such notifications is to poll a script on the server (using AJAX) on a given interval (perhaps every few seconds), to check if something has happened. However, this can be pretty network intensive, and you often make pointless requests, because nothing has happened.

The way Facebook does it is using the comet approach, rather than polling on an interval, as soon as one poll completes, it issues another one. However, each request to the script on the server has an extremely long timeout, and the server only responds to the request once something has happened. You can see this happening if you bring up Firebug's Console tab while on Facebook, with requests to a script possibly taking minutes. It is quite ingenious really, since this method cuts down immediately on both the number of requests, and how often you have to send them. You effectively now have an event framework that allows the server to 'fire' events.

Behind this, in terms of the actual content returned from those polls, it's a JSON response, with what appears to be a list of events, and info about them. It's minified though, so is a bit hard to read.

In terms of the actual technology, AJAX is the way to go here, because you can control request timeouts, and many other things. I'd recommend (Stack overflow cliche here) using jQuery to do the AJAX, it'll take a lot of the cross-compability problems away. In terms of PHP, you could simply poll an event log database table in your PHP script, and only return to the client when something happens? There are, I expect, many ways of implementing this.

Implementing:

Server Side:

There appear to be a few implementations of comet libraries in PHP, but to be honest, it really is very simple, something perhaps like the following pseudocode:

while(!has_event_happened()) {
   sleep(5);
}

echo json_encode(get_events());
  • The has_event_happened function would just check if anything had happened in an events table or something, and then the get_events function would return a list of the new rows in the table? Depends on the context of the problem really.

  • Don't forget to change your PHP max execution time, otherwise it will timeout early!

Client Side:

Take a look at the jQuery plugin for doing Comet interaction:

That said, the plugin seems to add a fair bit of complexity, it really is very simple on the client, perhaps (with jQuery) something like:

function doPoll() {
   $.get("events.php", {}, function(result) {
      $.each(result.events, function(event) { //iterate over the events
          //do something with your event
      });
      doPoll(); 
      //this effectively causes the poll to run again as
      //soon as the response comes back
   }, 'json'); 
}

$(document).ready(function() {
    $.ajaxSetup({
       timeout: 1000*60//set a global AJAX timeout of a minute
    });
    doPoll(); // do the first poll
});

The whole thing depends a lot on how your existing architecture is put together.

小ぇ时光︴ 2024-08-02 03:20:12

更新

随着我继续收到对此的支持,我认为有理由记住这个答案已经有 4 年了。 网络的发展速度非常快,所以请注意这个答案。


我最近遇到了同样的问题并研究了该主题。

给出的解决方案称为长轮询,要正确使用它,您必须确保 AJAX 请求具有“大”超时,并且始终在当前结束后(超时、错误或成功)发出此请求。

长轮询 - 客户端

在这里,为了保持代码简短,我将使用 jQuery:

function pollTask() { 

    $.ajax({

        url: '/api/Polling',
        async: true,            // by default, it's async, but...
        dataType: 'json',       // or the dataType you are working with
        timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
        cache: false

    }).done(function (eventList) {  

       // Handle your data here
       var data;
       for (var eventName in eventList) {

            data = eventList[eventName];
            dispatcher.handle(eventName, data); // handle the `eventName` with `data`

       }

    }).always(pollTask);

}

记住这一点很重要(来自 jQuery 文档):

在 jQuery 1.4.x 及更低版本中,XMLHttpRequest 对象将位于
如果请求超时,则状态无效; 访问任何对象成员
可能会抛出异常。 仅在 Firefox 3.0+ 中,脚本和 JSONP
请求不能因超时而取消; 该脚本将运行,即使
它在超时时间后到达。

长轮询 - 服务器

它不是用任何特定的语言,但它会是这样的:

function handleRequest () {  

     while (!anythingHappened() || hasTimedOut()) { sleep(2); }

     return events();

} 

这里,hasTimedOut将确保您的代码不会永远等待,并且anythingHappened,将检查是否发生任何事件。 sleep 用于在没有任何反应的情况下释放线程以执行其他操作。 events 将以 JSON 格式(或您喜欢的任何其他数据结构)返回事件字典(或您可能喜欢的任何其他数据结构)。

它确实解决了问题,但是,如果您像我在研究时一样担心可扩展性和性能,您可能会考虑我发现的另一个解决方案。

解决方案

使用套接字!

在客户端,为避免任何兼容性问题,请使用 socket.io。 它尝试直接使用套接字,并在套接字不可用时使用其他解决方案。

在服务器端,使用 NodeJS 创建一个服务器(示例 此处)。 客户端将订阅服务器创建的这个通道(观察者)。 每当需要发送通知时,都会在此通道中发布通知,并且订阅者(客户端)会收到通知。

如果您不喜欢此解决方案,请尝试 APE (Ajax Push Engine)。

希望我有所帮助。

Update

As I continue to recieve upvotes on this, I think it is reasonable to remember that this answer is 4 years old. Web has grown in a really fast pace, so please be mindful about this answer.


I had the same issue recently and researched about the subject.

The solution given is called long polling, and to correctly use it you must be sure that your AJAX request has a "large" timeout and to always make this request after the current ends (timeout, error or success).

Long Polling - Client

Here, to keep code short, I will use jQuery:

function pollTask() { 

    $.ajax({

        url: '/api/Polling',
        async: true,            // by default, it's async, but...
        dataType: 'json',       // or the dataType you are working with
        timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
        cache: false

    }).done(function (eventList) {  

       // Handle your data here
       var data;
       for (var eventName in eventList) {

            data = eventList[eventName];
            dispatcher.handle(eventName, data); // handle the `eventName` with `data`

       }

    }).always(pollTask);

}

It is important to remember that (from jQuery docs):

In jQuery 1.4.x and below, the XMLHttpRequest object will be in an
invalid state if the request times out; accessing any object members
may throw an exception. In Firefox 3.0+ only, script and JSONP
requests cannot be cancelled by a timeout; the script will run even if
it arrives after the timeout period.

Long Polling - Server

It is not in any specific language, but it would be something like this:

function handleRequest () {  

     while (!anythingHappened() || hasTimedOut()) { sleep(2); }

     return events();

} 

Here, hasTimedOut will make sure your code does not wait forever, and anythingHappened, will check if any event happend. The sleep is for releasing your thread to do other stuff while nothing happens. The events will return a dictionary of events (or any other data structure you may prefer) in JSON format (or any other you prefer).

It surely solves the problem, but, if you are concerned about scalability and perfomance as I was when researching, you might consider another solution I found.

Solution

Use sockets!

On client side, to avoid any compatibility issues, use socket.io. It tries to use socket directly, and have fallbacks to other solutions when sockets are not available.

On server side, create a server using NodeJS (example here). The client will subscribe to this channel (observer) created with the server. Whenever a notification has to be sent, it is published in this channel and the subscriptor (client) gets notified.

If you don't like this solution, try APE (Ajax Push Engine).

Hope I helped.

暗藏城府 2024-08-02 03:20:12

根据有关 Facebook 消息系统的幻灯片,Facebook 使用彗星技术将消息“推送”到网络浏览器。 Facebook 的 comet 服务器基于开源 Erlang Web 服务器 mochiweb 构建。

下图中,“通道集群”一词的意思是“彗星服务器”。

系统概述

许多其他大网站都建立了自己的comet服务器,因为每个公司的需求都有差异。 但在开源彗星服务器上构建自己的彗星服务器是一个好方法。

您可以尝试 icomet,这是一个使用 libevent 构建的 C1000K C++ comet 服务器。 icomet还提供了一个JavaScript库,使用起来很简单:

var comet = new iComet({
    sign_url: 'http://' + app_host + '/sign?obj=' + obj,
    sub_url: 'http://' + icomet_host + '/sub',
    callback: function(msg){
        // on server push
        alert(msg.content);
    }
});

icomet支持多种浏览器和操作系统,包括Safari(iOS、Mac)、IE(Windows)、Firefox、Chrome等。

According to a slideshow about Facebook's Messaging system, Facebook uses the comet technology to "push" message to web browsers. Facebook's comet server is built on the open sourced Erlang web server mochiweb.

In the picture below, the phrase "channel clusters" means "comet servers".

System overview

Many other big web sites build their own comet server, because there are differences between every company's need. But build your own comet server on a open source comet server is a good approach.

You can try icomet, a C1000K C++ comet server built with libevent. icomet also provides a JavaScript library, it is easy to use as simple as:

var comet = new iComet({
    sign_url: 'http://' + app_host + '/sign?obj=' + obj,
    sub_url: 'http://' + icomet_host + '/sub',
    callback: function(msg){
        // on server push
        alert(msg.content);
    }
});

icomet supports a wide range of Browsers and OSes, including Safari(iOS, Mac), IEs(Windows), Firefox, Chrome, etc.

肤浅与狂妄 2024-08-02 03:20:12

Facebook 使用 MQTT 而不是 HTTP。 推送比轮询更好。
通过 HTTP,我们需要不断轮询服务器,但通过 MQTT 服务器将消息推送到客户端。

MQTT 和 HTTP 之间的比较:http://www.youtube.com/watch?v=-KNPXPmx88E

注意:我的答案最适合移动设备。

Facebook uses MQTT instead of HTTP. Push is better than polling.
Through HTTP we need to poll the server continuously but via MQTT server pushes the message to clients.

Comparision between MQTT and HTTP: http://www.youtube.com/watch?v=-KNPXPmx88E

Note: my answers best fits for mobile devices.

没有心的人 2024-08-02 03:20:12

长轮询的一个重要问题是错误处理。
有两种类型的错误:

  1. 请求可能超时,在这种情况下客户端应立即重新建立连接。 这是长轮询中没有消息到达时的正常事件。

  2. 网络错误或执行错误。 这是一个实际错误,客户端应该优雅地接受并等待服务器重新上线。

主要问题是,如果您的错误处理程序也针对类型 2 错误立即重新建立连接,则客户端将对服务器进行 DOS。

带有代码示例的两个答案都忽略了这一点。

function longPoll() { 
        var shouldDelay = false;

        $.ajax({
            url: 'poll.php',
            async: true,            // by default, it's async, but...
            dataType: 'json',       // or the dataType you are working with
            timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
            cache: false

        }).done(function (data, textStatus, jqXHR) {
             // do something with data...

        }).fail(function (jqXHR, textStatus, errorThrown ) {
            shouldDelay = textStatus !== "timeout";

        }).always(function() {
            // in case of network error. throttle otherwise we DOS ourselves. If it was a timeout, its normal operation. go again.
            var delay = shouldDelay ? 10000: 0;
            window.setTimeout(longPoll, delay);
        });
}
longPoll(); //fire first handler

One important issue with long polling is error handling.
There are two types of errors:

  1. The request might timeout in which case the client should reestablish the connection immediately. This is a normal event in long polling when no messages have arrived.

  2. A network error or an execution error. This is an actual error which the client should gracefully accept and wait for the server to come back on-line.

The main issue is that if your error handler reestablishes the connection immediately also for a type 2 error, the clients would DOS the server.

Both answers with code sample miss this.

function longPoll() { 
        var shouldDelay = false;

        $.ajax({
            url: 'poll.php',
            async: true,            // by default, it's async, but...
            dataType: 'json',       // or the dataType you are working with
            timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
            cache: false

        }).done(function (data, textStatus, jqXHR) {
             // do something with data...

        }).fail(function (jqXHR, textStatus, errorThrown ) {
            shouldDelay = textStatus !== "timeout";

        }).always(function() {
            // in case of network error. throttle otherwise we DOS ourselves. If it was a timeout, its normal operation. go again.
            var delay = shouldDelay ? 10000: 0;
            window.setTimeout(longPoll, delay);
        });
}
longPoll(); //fire first handler
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文