使用Spring Boot进行SSE开发

春节 Boot 内置了对SSE(text/event-stream)的支持,我超想试试啊。你也是吧。

我们有一个适合您的SseEmitter。

简单的使用方法

每秒返回当前日期和时间的函数。异步执行的本身请参考 https://qiita.com/takkkun/items/1364fdaac8ae2b9fdc01。

@Service
class SseService {

  @Async
  fun emitDateTime(emitter: SseEmitter) {
    var finished = false
    while (!finished) {
      TimeUnit.SECONDS.sleep(1)

      try {
        sse.send(LocalDateTime.now().toString())
      }
      catch (e: IOException) {
        finished = true
      }
    }
  }
}

@Controller 
class SseController(private val service: SseService) {

  @RequestMapping(/* ... */)
  fun sse(): ResponseBodyEmitter {
    val emitter = SseEmitter()
    service.emitDateTime(emitter)
    return emitter
  }
}

在这个问题上,将会返回以下的响应。

$ curl -i 'http://localhost:8080/sse'
HTTP/1.1 200
Content-Type: text/event-stream;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 20 Jan 2020 07:01:31 GMT

data:2020-01-20T16:01:32.155751

data:2020-01-20T16:01:33.164949

data:2020-01-20T16:01:34.168721

data:2020-01-20T16:01:35.174836

data:2020-01-20T16:01:36.179743

...

超时

默认超时时间由Spring Boot确定。具体而言,通过”spring.mvc.async.request-timeout”属性来设置。单位为毫秒。

或者可以在SseEmitter的构造函数中指定。在这种情况下,构造函数中提供的值将被优先选择。

如果想要无限期,可以指定为0。

如果发生超时,将调用在SseEmitter#onTimeout中指定的回调函数,并抛出AsyncRequestTimeoutException。

断开与客户端的连接

我认为没有办法在客户端断开连接的瞬间立即检测到它。

但是,如果在客户端被断开的情况下调用SseEmitter#send方法,会抛出IOException(实际上应该是其子类ClientAbortException),因此可以通过捕获该异常来检测。

最终会调用SseEmitter#onError指定的回调函数,这样可以吗?

顺便提一下,如果在@Async标注的方法中发生未处理的异常,由于异步处理机制会记录日志,所以最好还是要正确处理异常(在Java中,IOException被认为是受检异常,因此必须强制处理)。

从服务器上完成

当调用SseEmitter#complete时,响应完成。

虽然我认为几乎都会从客户端断开连接,但根据用途不同,也有可能发生,所以只是预防起见。

广告
将在 10 秒后关闭
bannerAds