【问题标题】:Grails Server Sent EventGrails 服务器发送事件
【发布时间】: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]

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

【问题讨论】:

    标签: javascript grails server-sent-events


    【解决方案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 上的指南。

    【讨论】:

      猜你喜欢
      • 2013-12-29
      • 1970-01-01
      • 2015-09-24
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 2021-01-01
      • 1970-01-01
      相关资源
      最近更新 更多