简体   繁体   English

Grails服务器发送事件

[英]Grails Server Sent Event

I need to get Server-sent-events working with Grails. 我需要让服务器发送事件与Grails一起使用。 I feel like I am close, but just not quite there. 我觉得我很亲近,但就在那里。 The JavaScript request successfully reaches the controller, but it throws an error every time. JavaScript请求成功到达控制器,但每次都会抛出错误。 It keeps retrying once every 2 seconds or so (probably due to the error). 它每2秒钟左右重试一次(可能是由于错误)。

I need to send an event to the user when the server's session timer gets below 5 minutes. 当服务器的会话计时器低于5分钟时,我需要向用户发送一个事件。 I am trying to use HTML5's EventSource because I only want to send a single request to the server (multiple requests will reset the session timer each time). 我正在尝试使用HTML5的EventSource,因为我只想向服务器发送一个请求(多次请求每次都会重置会话计时器)。 According to Lean Java Engineering , HTML5 meets my need. 根据精益Java工程 ,HTML5满足了我的需求。

- Javascript - - 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 Controller - - 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 Console - - 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 Console - - 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]

Thanks in advance, Chris Hancock 在此先感谢Chris Hancock

In Grails controller, you need to change to something like this : 在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"
    }
}

In its basic form, the response should contain a "data:" line, followed by your message, followed by two "\\n" characters to end the stream: 在其基本形式中,响应应包含“data:”行,后跟您的消息,后跟两个“\\ n”字符以结束流:

data: My message\n\n

Now the response in console is : 现在控制台中的响应是:

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]

For more details you can look on http://www.html5rocks.com/en/tutorials/eventsource/basics/ . 有关详细信息,请访问http://www.html5rocks.com/en/tutorials/eventsource/basics/

UPDATE UPDATE

Why does it throw an error every time, though? 为什么每次都会抛出一个错误呢?

There can be different reason for error for example : network timeout. 可能有不同的错误原因,例如:网络超时。 In our case, it is due to connection being closed between server and browser. 在我们的例子中,这是由于服务器和浏览器之间的连接关闭。

Why does it continually ping the server? 为什么它不断ping服务器?

The connection between server and browser is closed after browser gets the data . 浏览器获取the data后,服务器和浏览器之间的连接将关闭。 So the browser tries to reconnect roughly 3 seconds after each connection is closed. 因此,浏览器尝试在每个连接关闭后大约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. 我认为当JavaScript第一次运行时,HTML5应该连接一次,并且只要控制器发送它就接收事件。

It is supposed to have always connection with server but not connect once. 它应该始终与服务器连接但不能连接一次。
Yes, it receives events as long as the controller sent them message. 是的,只要控制器发送消息,它就会收到事件。 But in our case the server/controller just send data: the data\\n\\n and connection is closed. 但在我们的例子中,服务器/控制器只发送data: the data\\n\\n和连接关闭。
In order to receive message continuously, you need to have loop in the controller action. 为了连续接收消息,您需要在控制器操作中进行循环。 For example : 例如 :

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"
    }
}

You can also use while(true) loop. 您也可以使用while(true)循环。

If you want to more about onerror , you can see this link http://www.htmlgoodies.com/beyond/reference/receive-updates-from-the-server-using-the-eventsource.html . 如果您想了解有关onerror更多信息,可以在http://www.htmlgoodies.com/beyond/reference/receive-updates-from-the-server-using-the-eventsource.html上看到此链接。
According to above link, 根据以上链接,

There is an onerror() event handler, but it's not as useful as you might think. 有一个onerror()事件处理程序,但它没有你想象的那么有用。 It can however tell us some things about what's happening, thanks to the EventSource's readyState property. 然而,由于EventSource的readyState属性,它可以告诉我们有关正在发生的事情的一些事情。 For instance, a value of EventSource.CONNECTING means that the connection was lost and the EventSource is attempting to reconnect. 例如,EventSource.CONNECTING的值意味着连接丢失且EventSource正在尝试重新连接。 If something goes very wrong, a value of EventSource.CLOSED will let you know. 如果出现问题,可以通过EventSource.CLOSED的值告诉您。 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. 可以通过eventSource或eventTarget属性访问EventSource,因为它们都指向同一个对象。

Note that in Grails 3.2 there is native support for Server Sent Events via the RxJava plugin . 请注意,在Grails 3.2中,通过RxJava插件对Server Sent Events提供本机支持。

An example application is available too, as well as a guide on the grails guides page . 还提供了一个示例应用程序 ,以及grails指南页面上的指南

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM