Grails 服务器发送事件
Posted
技术标签:
【中文标题】Grails 服务器发送事件【英文标题】:Grails Server Sent Event 【发布时间】:2015-06-16 11:57:53 【问题描述】:我需要让服务器发送的事件与 Grails 一起使用。我觉得我很接近,但并不完全在那里。 javascript 请求成功到达控制器,但每次都抛出错误。它会每 2 秒左右重试一次(可能是由于错误)。
当服务器的会话计时器低于 5 分钟时,我需要向用户发送一个事件。我正在尝试使用 html5 的 EventSource,因为我只想向服务器发送一个请求(多个请求每次都会重置会话计时器)。根据Lean Java Engineering,HTML5 满足我的需求。
-Javascript-
console.log("Starting eventSource");
var eventSource = new EventSource("SSETest/push");
console.log("Started eventSource");
eventSource.onmessage = function(event) console.log("Message received: " + event.data); ;
eventSource.onopen = function(event) console.log("Open " + event); ;
eventSource.onerror = function(event) console.log("Error " + event); ;
console.log("eventState: " + eventSource.readyState);
// Stop trying after 10 seconds of errors
setTimeout(function() eventSource.close();, 10000);
-Grails 控制器-
package sessionManager
class SSETestController
def push =
println "$request made it!"
response.setContentType("text/event-stream, charset=UTF-8")
response << "data: the data"
render "HI"
-Grails 控制台-
org.apache.catalina.core.ApplicationHttpRequest@4f889fad made it!
org.apache.catalina.core.ApplicationHttpRequest@13f78b8c made it!
org.apache.catalina.core.ApplicationHttpRequest@4b50734c made it!
org.apache.catalina.core.ApplicationHttpRequest@4c4bde24 made it!
-JavaScript 控制台-
Starting eventSource
Started eventSource
eventState: 0
Open [object Event]
Error [object Event]
Open [object Event]
Error [object Event]
Open [object Event]
Error [object Event]
Open [object Event]
Error [object Event]
提前致谢, 克里斯·汉考克
【问题讨论】:
【参考方案1】:在 Grails 控制器中,您需要更改为以下内容:
package sessionManager
class SSETestController
def push =
println "$request made it!"
response.setContentType("text/event-stream, charset=UTF-8")
//response << "data: the data\n\n"
render "data: the data\n\n"
在其基本形式中,响应应该包含一个“data:”行,然后是您的消息,然后是两个“\n”字符以结束流:
data: My message\n\n
现在控制台的响应是:
Starting eventSource
Started eventSource
eventState: 0
Open [object Event]
Message received: the data
Error [object Event]
Open [object Event]
Message received: the data
Error [object Event]
Open [object Event]
Message received: the data
Error [object Event]
Open [object Event]
Message received: the data
Error [object Event]
更多详情可以关注http://www.html5rocks.com/en/tutorials/eventsource/basics/。
更新
为什么每次都会抛出错误呢?
可能有不同的错误原因,例如:网络超时。在我们的例子中,这是由于服务器和浏览器之间的连接被关闭。
为什么它会不断地 ping 服务器?
浏览器获取the data
后服务器与浏览器的连接关闭。因此浏览器会在每次连接关闭后大约 3 秒尝试重新连接。
我认为 HTML5 应该在 JavaScript 运行时连接一次 第一次,只要控制器发送,就接收事件 他们。
它应该始终与服务器连接但不连接一次。
是的,只要控制器向它们发送消息,它就会接收事件。但在我们的例子中,服务器/控制器只发送data: the data\n\n
并关闭连接。
为了连续接收消息,您需要在控制器动作中有循环。例如:
package sessionManager
class SSETestController
def push =
println "$request made it!"
response.setContentType("text/event-stream, charset=UTF-8")
for(int i = 0 ; i < 10 ; i++)
render "data: the data\n\n"
Thread.sleep(1000)
render "data: finished\n\n"
你也可以使用while(true)
循环。
如果您想了解更多关于onerror
的信息,可以查看此链接http://www.htmlgoodies.com/beyond/reference/receive-updates-from-the-server-using-the-eventsource.html。
根据上面的链接,
有一个 onerror() 事件处理程序,但它没有你有用 可能会想。然而,它可以告诉我们一些关于什么是 这要归功于 EventSource 的 readyState 属性。为了 例如,EventSource.CONNECTING 的值表示连接 丢失并且 EventSource 正在尝试重新连接。如果有什么 出错了,EventSource.CLOSED 的值会让你知道。 除此之外,您无法获得太多信息,因为没有错误 查询的对象。相反,传递的是事件对象本身 到处理程序。 EventSource 可以通过 eventSource 或 eventTarget 属性,因为两者都指向同一个对象。
【讨论】:
感谢您的回答!但是,为什么每次都会抛出错误?为什么它会不断地 ping 服务器?我认为 HTML5 应该在 JavaScript 第一次运行时连接一次,并且只要控制器发送事件并加载页面就可以接收事件? 谢谢你,拉姆夏兰!感谢您的回复! Ramsharan,如果我按照您的最后一个示例(使用 for 循环),我可以看到在控制器操作实际完成(最后一个渲染行)之前不会发送消息。如果是这样,浏览器会立即收到所有消息。有没有办法在阻止连接关闭的同时释放消息?【参考方案2】:请注意,在 Grails 3.2 中,通过 RxJava plugin 原生支持服务器发送事件。
还提供example application,以及grails guides page 上的指南。
【讨论】:
以上是关于Grails 服务器发送事件的主要内容,如果未能解决你的问题,请参考以下文章
ReactJS:无法在一次 POST 调用中发送 JSON 数据和 PDF 文件