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

作者站长头像
站长
· 阅读数 11

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

回复
1个回答
avatar
test
2024-08-11

解决了问了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)。这使你能够在知道响应类型的情况下更轻松地处理数据,从而实现逐条返回或一次性返回。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容