我看到Akka模块的描述说Play有很好的Comet支持,但我之前从未使用过Comet,我在Play的文档中找不到它。它在Play中如何运作?
我花了几个小时两天来搞清楚这一点,所以我想与其他Play初学者分享这些信息。
答案 0 :(得分:20)
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构建节点或连接字符串相比,结果更容易阅读和维护。总的来说,一旦你知道哪些位是相关的,它就非常简单。
答案 1 :(得分:7)
有很多方法可以在网络应用程序中实现服务器推送或Comet,其中最常见的是Long Polling,因为它在大多数现代浏览器中都得到了很好的支持。
播放主要通过suspend(time);
功能实现长轮询。这个函数做了两件非常重要的事情
它保持HTTP请求打开,并在指定的时间内重试该操作。这允许您保留HTTP请求并继续重试操作,直到您想要通知浏览器的某些事情
非常重要的是,当请求被暂停时,线程被释放。这意味着http请求不会为每个挂起的请求保留一个打开的线程。
当播放处于DEV模式时,它只能在单个线程上运行,但您可以(我已经尝试)在示例聊天应用程序上运行数十个用户而不会挂起服务器,或者用户被阻止请求。
暂停方法是唯一可以帮助Comet的方法。如果您运行示例聊天应用程序并打开客户端,您会注意到120秒后,请求将超时。示例应用程序不会重试该请求。您必须自己构建的长轮询技术的客户端。
Guillaume在论坛中提到示例聊天应用程序只是一个可以使用多长轮询的演示。所以我不认为Play可以证明有很好的Comet支持,这只是朝着正确方向迈出的一步。
答案 2 :(得分:1)
您可以在Akka中使用Mist进行Servlet 3.00或Jetty7 Continuations支持的服务器推送(Comet):http://doc.akkasource.org/http#Mist%20-%20Lightweight%20Asynchronous%20HTTP