WebClient如何根据接口返回类型是text/event-stream则逐条返回,否则一次性全部返回?

我想请求别人的接口,但是我不知道它的接口返回类型是啥,所以我的需求是:如何根据接口返回类型是text/event-stream则逐条返回,否则一次性全部返回?

阅读 1.8k
2 个回答

解决了问了ChatGpt和文心一言,最后是文心一言解决了我的问题,使用toEntityFlux,不要使用exchangeToMonoexchangeToFlux

return requestSpec
    .retrieve()
    .onStatus(HttpStatusCode::isError, clientResponse -> clientResponse.createException().flatMap(Mono::error))
    .toEntityFlux(String.class) // 注意这里使用了toEntityFlux而不是直接bodyToFlux
    .flatMap(responseEntity -> {
        HttpHeaders headers2 = responseEntity.getHeaders();
        MediaType contentType2 = headers2.getContentType();
        if (MediaType.TEXT_EVENT_STREAM.isCompatibleWith(contentType2)) {
            // 如果是SSE,则直接返回Flux<String>作为响应体
            return Mono.just(ResponseEntity.ok()
                    .headers(headers2) // 可以选择性地保留或修改响应头
                    .contentType(MediaType.TEXT_EVENT_STREAM)
                    .body(Flux.from(Objects.requireNonNull(responseEntity.getBody()))));
        } else {
            // 如果不是SSE,你可以根据需要处理响应体
            // 例如,这里我们简单地返回整个响应体作为一个字符串(注意:这通常不是最佳实践)
            return Objects.requireNonNull(responseEntity.getBody()).reduce("", String::concat)
                    .map(body2 -> ResponseEntity.ok()
                            .headers(headers2)
                            .body(body2)); // 注意:这里返回的是Mono<String>,而不是Flux<String>

            // 或者,如果你仍然想以Flux的形式返回,但不想逐条处理,你可以这样做:
            // return Flux.just(responseEntity.getBody().toStream().collect(Collectors.toList()))
            //     .map(list -> ResponseEntity.ok().body(Flux.fromIterable(list)));
            // 但这实际上并不是处理SSE的正确方式
        }
    })
    .onErrorResume(WebClientResponseException.class, e -> {
        return Mono.just(ResponseEntity.status(e.getStatusCode())
                .headers(e.getHeaders())
                .body(e.getResponseBodyAsString()));
    })
    .onErrorResume(e -> {
        // 处理其他异常,并将错误信息添加到响应头中
        HttpHeaders errorHeaders = new HttpHeaders();
        errorHeaders.set("error-status", "500");
        errorHeaders.set("error-message", e.getMessage());
        return Mono.just(ResponseEntity.status(500)
                .headers(errorHeaders)
                .body(Map.of(
                        "status", "500",
                        "error", "Internal Server Error",
                        "message", e.getMessage()
                )));
    });

下面是文心一言的回答:
这是因为 exchangeToMono 和 exchangeToFlux 的行为方式不同,而 toEntityFlux 提供了更多信息,让你更容易根据响应类型来处理数据。

以下是原因和差异的详细解释:

exchangeToMono 和 exchangeToFlux:
exchangeToMono:用于处理单个响应对象,将整个响应体作为一个 Mono 来处理。它适合一次性处理整个响应体的情况。
exchangeToFlux:用于处理多个响应对象,将响应体作为一个 Flux 来处理。它适合逐条处理响应体的数据。

toEntityFlux:

toEntityFlux:返回一个包含完整响应信息(包括状态码、头信息和响应体)的 Mono<ResponseEntity<Flux<T>>>。这使你能够更灵活地根据响应头信息(如 Content-Type)来处理响应体。

toEntityFlux 提供了对完整响应的访问权限,包括头信息(如 Content-Type)。这使你能够在知道响应类型的情况下更轻松地处理数据,从而实现逐条返回或一次性返回。

这是你想表达的意思不?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fetch Example</title>
</head>
<body>
    <script>
        async function fetchAndProcess(url) {
            try {
                const response = await fetch(url);
                const contentType = response.headers.get('Content-Type');

                if (contentType && contentType.includes('text/event-stream')) {
                    // 逐条处理text/event-stream
                    const eventSource = new EventSource(url);
                    eventSource.onmessage = function(event) {
                        console.log('Received event:', event.data);
                    };
                    eventSource.onerror = function(err) {
                        console.error('EventSource failed:', err);
                        eventSource.close();
                    };
                } else {
                    // 一次性处理其他类型
                    const responseText = await response.text();
                    console.log('Received response:', responseText);
                }
            } catch (error) {
                console.error('Fetch error:', error);
            }
        }

        // 替换为你的接口URL
        const url = 'http://example.com/api';
        fetchAndProcess(url);
    </script>
</body>
</html>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题