【问题标题】:How does Play!'s Comet support work?Play! 的 Comet 支持如何工作?
【发布时间】:2011-05-29 13:14:18
【问题描述】:

我看到 Akka 模块的描述说 Play 有很好的 Comet 支持,但我以前从未使用过 Comet,而且我在 Play 的文档中找不到任何提及它的内容。它在 Play 中是如何工作的?


我花了两天多的几个小时来解决这个问题,所以我想将这些信息分享给其他 Play 初学者。

【问题讨论】:

  • 不要在标题中加上“已解决”,只需将您自己的答案标记为已接受即可。
  • 过去的美好时光,论坛是答案的来源,获得“[已解决]”是对无尽挫折的胜利:D

标签: comet playframework


【解决方案1】:

Play 包含一个示例聊天应用程序,用于演示如何使用 Comet。这个例子并没有解释发生了什么,所以这就是我想出来的。

型号

为了让其他人找到您发送的新更新,它们需要存储在某个地方。可以想象,这可能在缓存中,甚至在控制器本身中,但数据库将是最安全的选择,因此您需要一个模型。他们还需要一种方法来确定哪些更新对他们来说是新的,这意味着您可能需要一个日期字段(另请参阅:Last update timestamp with JPA)。 Chat 示例使用了一个简单的模型:

@Entity
public class Message extends Model {     
    public String user;
    public Date date;
    public String text;

    public Message(String user, String text) {
        this.user = user;
        this.text = text;
        this.date = new Date();
    }       
}

控制器

控制器需要两种方法来方便 Comet。一个发布新数据的地方,它没有做任何特别的事情:

public static void postMessage(String message) {
    new Message(session.get("nick"), message).save();
}

还有一个用于检索更新:

public static void newMessages() {
    List<Message> messages = Message.find("date > ?", request.date).fetch();
    if (messages.isEmpty()) {
        suspend("1s");
    }
    renderJSON(messages);
}

这里的关键位是suspend("1s"),它使 HTTP 请求保持打开状态,每秒检查一次新数据。

查看

视图具有三个职责——发送新数据、获取更新然后呈现这些更新。

发送,就像相应的控制器动作一样,没有做任何特别的事情:

$('#send').click(function(e) {
    var message = $('#message').val();
    $('#message').val('');
    $.post('@{postMessage()}', {message: message}); 
});

获取更新是神奇之处:

// Retrieve new messages
var getMessages = function() {
    $.ajax({
        url: '@{newMessages()}',
        success: function(messages) {
            $(messages).each(function() {
                display(this);
            });
        },
        complete: function() {
            getMessages();
        },
        dataType: 'json'
    });
}
getMessages();

getMessages() 被调用一次以开始工作,然后在每次成功请求后递归调用自身。它获取查找新消息的newMessages() 操作,如果没有任何消息,它将保持请求处于打开状态,直到它有要报告的内容。找到新消息时,会将 JSON 数据传递给 display 函数:

var display = function(message) {
    $('#thread').append(tmpl('message_tmpl', {message: message}));
}

display 函数将JavaScript Micro-Template 应用于 JSON 数据以呈现新消息。不需要使用微模板,但它确实工作得很好。它们直接包含在将要使用它们的页面模板中:

<script type="text/html" id="message_tmpl">
    <div class="message <%= message.user == '${session.nick}' ? 'you' : '' %> <%= message.user == 'notice' ? 'notice' : '' %>">
        <h2><%= message.user %></h2>
        <p><%= message.text.replace('\n', '<br/>') %></p>
    </div>
</script>

type="text/html" 导致浏览器、搜索引擎和屏幕阅读器忽略整个 script 块。结果比使用 jQuery 构建节点或连接字符串更容易阅读和维护。总的来说,一旦您知道哪些位是相关的,就很简单了。

【讨论】:

  • 你确定这与彗星框架有关吗?我以为这只是本机解决方案。
  • @niels - 我不确定你的意思,特别是因为我刚刚开始,但 Comet 是向客户发送更新的总称,这就是 Play 实现它的方式。
  • 你是对的。我以为有一个名为 comet 的现有框架。
  • @lhk 它没有从 java 调用 javascript; Java实际上被用于生成javascript。在这种情况下,模板引擎正在插入用于发布新消息的 url。如果您要在页面上“查看源代码”,您会看到类似$.post('/messages', {message: message});
  • 你不会遇到 JavaScript 堆栈溢出吗? JavaScript 没有尾递归优化。
【解决方案2】:

有很多方法可以在 Web 应用程序中实现 server-push 或 Comet,其中最常见的一种是 Long Polling,因为它在大多数现代浏览器中都得到了很好的支持。

Play主要通过suspend(time);函数实现长轮询。这个函数做了两件非常重要的事情

  1. 它保持 HTTP 请求打开并在指定的时间内重试操作。这允许您保留 HTTP 请求并继续重试该操作,直到发生您想要通知浏览器的事情

  2. 而且非常重要的是,线程在请求​​被挂起时被释放。这意味着 http 请求不会为每个挂起的请求保留一个打开的线程。

当 play 处于 DEV 模式时,它仅在单个线程上运行,但您可以(并且我已经尝试过)在示例聊天应用程序上运行数十个用户,而不会导致服务器挂起或用户收到阻止的请求。

suspend 方法是 play 真正帮助 Comet 的唯一方法。如果您运行示例聊天应用程序并让客户端保持打开状态,您会注意到 120 秒后,请求将超时。示例应用程序不会重试该请求。您必须自己构建长轮询技术的客户端。

Guillaume 在论坛中提到,示例聊天应用程序只是一个演示可以使用多长时间的轮询。因此,我认为 Play 无法证明拥有出色的 Comet 支持,这只是朝着正确方向迈出的一步。

【讨论】:

  • 感谢您的澄清。我能找到的关于 Play 和 Comet 的唯一信息是 akka author said
  • 你 120 多岁的数字来自哪里?我刚刚尝试在 Firefox 和 Chrome 中让我的应用程序会话(以 Chat 示例为模型)闲置 30 分钟,但两者仍然有效。 Chrome 甚至用它的微调器来指示它。不过,在我的测试期间,Firefox 确实错过了几次更新。
  • 可能是 IE。它似乎在一段时间后超时。我见过的一些代理和负载均衡器会发生类似的超时。
【解决方案3】:

您可以在 Akka 中使用 Mist 进行由 Servlet 3.00 或 Jetty7 支持的服务器推送 (Comet) Continuations:http://doc.akkasource.org/http#Mist%20-%20Lightweight%20Asynchronous%20HTTP

【讨论】:

  • Akka 已切换到 Play! 2.0 和迷你游戏!彗星2.0
猜你喜欢
  • 2012-03-09
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多