Grails 服务器发送事件

Grails Server Sent Event

我需要让 Server-sent-events 与 Grails 一起工作。我觉得我很接近,但还不完全在那里。 JavaScript请求成功到达controller,但是每次都报错。它每 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]

提前致谢, 克里斯·汉考克

在 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/

更新

Why does it throw an error every time, though?

可能有不同的错误原因,例如:网络超时。在我们的例子中,这是由于服务器和浏览器之间的连接被关闭。

Why does it continually ping the server?

浏览器获取the data后服务器与浏览器的连接关闭。因此浏览器会在每次连接关闭后大约 3 秒尝试重新连接。

I thought HTML5 was supposed to connect once when the JavaScript ran the first time, and receive events as long as the controller sent them.

应该一直连接服务器,但一次都没有连接。
是的,只要控制器向它们发送消息,它就会接收事件。但在我们的例子中 server/controller 只是发送 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 的信息,可以查看此 link http://www.htmlgoodies.com/beyond/reference/receive-updates-from-the-server-using-the-eventsource.html
根据上面link,

There is an onerror() event handler, but it's not as useful as you might think. It can however tell us some things about what's happening, thanks to the EventSource's readyState property. For instance, a value of EventSource.CONNECTING means that the connection was lost and the EventSource is attempting to reconnect. If something goes very wrong, a value of EventSource.CLOSED will let you know. Other than that, you can't get much information as there is no error object to query. Instead, it is the event object itself that is passed to the handler. The EventSource may be accessed via the eventSource or eventTarget properties, since both point to the same object.

请注意,在 Grails 3.2 中,通过 RxJava plugin.

原生支持服务器发送的事件

一个example application is available too, as well as a guide on the grails guides page.