gpt4 book ai didi

grails - 服务器发送事件与 Grails - 如何防止 Controller 关闭连接

转载 作者:行者123 更新时间:2023-12-02 15:19:44 26 4
gpt4 key购买 nike

这个问题与:Grails Server Sent Event

我正在尝试在 grails v2.4 上实现 SSE,但我无法阻止 grails 关闭连接。
我所拥有的是:

import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class SseController {
def heartbeat = {
response.contentType = 'text/event-stream'
response.characterEncoding = 'UTF-8'
response.setHeader('Cache-Control', 'no-cache')
response.setHeader('Connection', 'keep-alive')
response << 'data: 12345\n\n'
response.flushBuffer()

def grails_request = request.getAttribute(GA.WEB_REQUEST)
grails_request.setRenderView(false)
}
}

但如果我这样做,客户端浏览器在订阅 channel 后会报告以下内容:
Open [object Event]
Data:12345
Error [object Event]

我得到的错误是由于在 Controller 中完成“心跳”操作后连接关闭。
如果我添加一个while循环来保持 Action 像这样运行......
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class SseController {
def heartbeat = {
response.contentType = 'text/event-stream'
response.characterEncoding = 'UTF-8'
response.setHeader('Cache-Control', 'no-cache')
response.setHeader('Connection', 'keep-alive')
response << 'data: 12345\n\n'
response.flushBuffer()

def grails_request = request.getAttribute(GA.WEB_REQUEST)
grails_request.setRenderView(false)

while(true) {
sleep(10000)
}
}
}

...然后客户端浏览器永远不会收到数据。 response.flushBuffer()命令没有任何作用。
连接没有关闭,没关系,但数据不会发送到客户端。

因此,正确的解决方案将包括摆脱 while 循环,同时告诉 Grails 在执行操作后不要关闭连接。

任何人都知道如何做到这一点?
顺便说一句,我尝试同时使用 Tomcat 和 Jetty 服务器,结果在两者上都是一样的; Controller Action 完成后,所有消息都会立即发送。

最佳答案

Server Sent Events has been implemented for Grails 3.2 的 native 支持.

插件源可以找到here

如果您希望继续使用 Grails 2,您可以将此插件移植到 Grails 2。但是,如果您打算推出自己的解决方案,那么实现的关键是您需要启动非阻塞异步响应。您可以在 RxResultTransformer 中看到这是如何完成的。插件的类。

关键部分是这样的:

webRequest.setRenderView(false)

// Create the Async web request and register it with the WebAsyncManager so Spring is aware
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request)

AsyncWebRequest asyncWebRequest = new AsyncGrailsWebRequest(
request,
response,
webRequest.servletContext)

asyncManager.setAsyncWebRequest(asyncWebRequest)
// Start async processing and create the GrailsAsync object
asyncWebRequest.startAsync()
request.setAttribute(GrailsApplicationAttributes.ASYNC_STARTED, true)
GrailsAsyncContext asyncContext = new GrailsAsyncContext(asyncWebRequest.asyncContext, webRequest)
response.setContentType(CONTENT_TYPE_EVENT_STREAM);
response.flushBuffer()

然后,您需要启动另一个容器线程,该线程会定期将数据发送回客户端。该插件使用 RxJava 执行此操作:
Observable newObservable = Observable.create( { Subscriber newSub ->
asyncContext.start {
// your code here
}
} as Observable.OnSubscribe)
newObservable.subscribe(subscriber)

如果您不想使用 RxJava,那么您可以简单地使用 while 循环或任何适合您的方式。
asyncContext.start {
while(true) {
// write event
}
}

关于grails - 服务器发送事件与 Grails - 如何防止 Controller 关闭连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39563515/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com