在生成的事件流值中找不到 Spring 的 SSEmitter 事件 "name" 属性

Cannot find Spring's SSEmitter Event "name" property in the resulting event-stream value

我在 Spring 框架内使用服务器发送事件 (SSE)。我可以在 chrome 浏览器和后端使用 jersey-media-sse

中使用 javascript 代码注册到这些流
  <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-sse</artifactId>
        <version>2.21</version>
    </dependency>

现在的问题是 Spring 的 SSEmitter 逻辑没有按预期设置事件的 name 属性。在下面的发送逻辑中使用 setter 似乎很直观 - 但 consuming/receiving 客户端的结果值会产生 name:null。该属性仍然可用 - 但很难在大 JSON 字符串的三个 data 字段之一中找到。

请阅读以下内容以详细了解问题


这是应该产生 SSEvent 流的端点片段

  @CrossOrigin(Resources.Origins.FRONTEND)
  @GetMapping(GET_LOG + "/stream")
  public SseEmitter subscribeToLogEventStream() {
    Optional<SseEmitter> sseEmitter = createAndSubscribe(EVENT_IDENTIFIER);
    return sseEmitter.orElse(null);
  }

发送事件的逻辑如下

 void sendEvent(SseEmitter sseEmitter, String toolId, String message) {
    SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event()
            .data(message, MediaType.TEXT_EVENT_STREAM)
            .name(toolId);
    Set<ResponseBodyEmitter.DataWithMediaType> event = sseEventBuilder.build();

    try {
      sseEmitter.send(event);
      log.debug("Sending SSEvent");
    } catch (ClientAbortException e) {
      log.error("Stream connection is not longer established. Aborting.", e);
    } catch (IOException e) {
      log.error("Server sent event emitter failed", e);
    }

  }

在后端接收此事件,InboundEvent 对象产生这些属性

请注意 name 字段恰好为空,尽管它已在发送逻辑中设置

 SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event()
                .data(message, MediaType.TEXT_EVENT_STREAM)
                .name(toolId);

实际上 name 字段是在以下 JSON 字符串的 3rd 数据字段中定义的。

奇怪格式的事件流数据

    [
  {
    "data": "data:",
    "mediaType": {
      "type": "text",
      "subtype": "plain",
      "parameters": {
        "charset": "UTF-8"
      },
      "qualityValue": 1.0,
      "concrete": true,
      "wildcardType": false,
      "charSet": "UTF-8",
      "charset": "UTF-8",
      "wildcardSubtype": false
    }
  },
  {
    "data": "Wed Jan 24 18:17:13 CET 2018>ERROR: Finishing execution but still unhappy",
    "mediaType": {
      "type": "text",
      "subtype": "event-stream",
      "parameters": {},
      "qualityValue": 1.0,
      "concrete": true,
      "wildcardType": false,
      "charSet": null,
      "charset": null,
      "wildcardSubtype": false
    }
  },
  {
    "data": "\nevent:foo\n\n", // <<<< Name definition (suffixed with event)
    "mediaType": {
      "type": "text",
      "subtype": "plain",
      "parameters": {
        "charset": "UTF-8"
      },
      "qualityValue": 1.0,
      "concrete": true,
      "wildcardType": false,
      "charSet": "UTF-8",
      "charset": "UTF-8",
      "wildcardSubtype": false
    }
  }
]

我刚刚发现 .send() 方法不需要 SseEmitter.SseEventBuilder 创建的事件 - 不,它需要构建器本身。这对我来说有点不直观,因此很长一段时间都没有意识到。

 void sendEvent(SseEmitter sseEmitter, String toolId, String message) {
    SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event()
            .data(message)
            .name(toolId);

    try {
      sseEmitter.send(sseEventBuilder );
      log.debug("Sending SSEvent");
    } catch (ClientAbortException e) {
      log.error("Stream connection is not longer established. Aborting.", e);
    } catch (IOException e) {
      log.error("Server sent event emitter failed", e);
    }

  }