调试来自Chrome和Postman中的Spring的服务器发送的事件流

根据Spring文档,当返回时,Spring应该为订阅返回的每个元素发出一个服务器发送的事件。Flux

下面是一个示例性的 REST 控制器:

package myapp.controller;

import myapp.MyOutput;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/api/v1/test")
@Api(tags = "Test API")
public class TestController {

    @ApiOperation(
        value = "Test",
        response = MyOutput.class,
        produces = MediaType.TEXT_EVENT_STREAM_VALUE
    )
    @RequestMapping(
        value = "",
        method = RequestMethod.PATCH,
        produces = MediaType.TEXT_EVENT_STREAM_VALUE
    )
    @ApiResponses(
        value = {
            @ApiResponse(code = 200, message = "Service execution successful"),
            @ApiResponse(code = 400, message = "Bad input data"),
            @ApiResponse(code = 500, message = "An internal server error occurred."),
            @ApiResponse(code = 503, message = "The service is not available.")
        }
    )
    public ResponseEntity<Flux<MyOutput>> test() {
        return ResponseEntity.ok().header("Connection", "Keep-Alive")
            .body(Flux.range(0, 1000)
                .delayElements(Duration.ofSeconds(1))
                .map(MyOutput::new)
            );
    }
}

使用 wget 的示例响应:

data:{"recordCount":0}

data:{"recordCount":148}

data:{"recordCount":226}

data:{"recordCount":266}

data:{"recordCount":272}

data:{"recordCount":286}

data:{"recordCount":287}

data:{"recordCount":293}

data:{"recordCount":294}

当使用Chrome或Postman调试端点时,客户端似乎将事件解释为分块响应的一部分 - 而不是事件流。我已确认响应数据是相同的,并且需要预期的时间量。请参阅下面 Chrome 网络标签中的屏幕截图:

Chrome Developer Networking Tab -> Headers

“事件流 -”选项卡为空:

Chrome Developer Networking Tab -> EventStream Chrome Developer Networking Tab -> Timing


将其与 http://www.emojitracker.com/ 等网站的标题进行比较:

Chrome Developer Networking Tab -> Headers

其中“事件流”选项卡正确显示事件:

Chrome Developer Networking Tab -> EventStream


重要的事实是,当使用 带有 的 Spring 端点时,我可以使用 在预期的时间内成功接收每个事件。因此,这些事件似乎缺少Chrome期望从服务器发送的事件流中获得的某种形式的配置 - 但哪种配置呢?WebClient.bodyToFlux


答案 1

首先,在浏览器中使用 EventSource 时会执行 GET 请求,因此使用 PATCH 在浏览器中并不真正兼容。

如果我们获取您的代码并在GET中更改PATCH,然后我们创建一个简单的页面页面:

<html lang="fr">
    <head>
        <title>Test SSE</title>
        <script>
            const evtSource = new EventSource("/api/v1/test");
            evtSource.onmessage = function(event) {
                const newElement = document.createElement("li");
                const eventList = document.getElementById("results");
                newElement.textContent = "message: " + event.data;
                eventList.appendChild(newElement);
            }
        </script>
    </head>
    <body>
        <ul id="results">

        </ul>
    </body>
</html>

让您的应用程序提供此静态文件,并在 chrome 中打开它。您将在“事件”选项卡中正确看到事件。但是,如果直接请求 /api/v1/test,则会在页面中显示此事件,但不在“事件”选项卡中。我假设事件选项卡拦截事件源对象,如果没有创建事件源,则不会使用。


答案 2

推荐