数据缓冲区限制异常:超过了WebFlux错误缓冲最大字节数的限制。

118

在发送文件时,我会收到一个字节数组。但是使用webflux接收数组时总是出现问题。

抛出的错误如下:

org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
    at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:101)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException

你知道如何在webflux中解决这个问题吗?


3
https://github.com/spring-projects/spring-framework/issues/23961 - Martin Tarjányi
您也可以参考:https://www.baeldung.com/spring-webflux-databufferlimitexception - user2173372
大多数(全部?)答案都建议配置缓冲区的大小。我认为没有其他选择。这感觉像是WebClient API的失败。实现应该在需要时增加后备缓冲区,就像ArrayList在需要时会增加后备数组一样。 - JohnC
14个回答

0

如果您不想全局更改webClient的默认设置,可以使用以下方法手动合并多个DataBuffer

webClient
        .method(GET)
        .uri("<uri>")
        .exchangeToMono(response -> {
          return response.bodyToFlux(DataBuffer.class)
              .switchOnFirst((firstBufferSignal, responseBody$) -> {
                assert firstBufferSignal.isOnNext();
                return responseBody$
                    .collect(() -> requireNonNull(firstBufferSignal.get()).factory().allocateBuffer(), (accumulator, curr) -> {
                      accumulator.ensureCapacity(curr.readableByteCount());
                      accumulator.write(curr);
                      DataBufferUtils.release(curr);
                    })
                    .map(accumulator -> {
                      final var responseBodyAsStr = accumulator.toString(UTF_8);
                      DataBufferUtils.release(accumulator);
                      return responseBodyAsStr;
                    });
              })
              .single();
        });

上面的代码将所有的 DataBuffer 聚合成一个单独的 DataBuffer,然后将最终的 DataBuffer 转换为字符串。请注意,由于接收到的 DataBuffers 可能没有所有字节来构造一个字符(在 UTF-8 字符的情况下,每个字符最多可以占用 4 个字节),因此这个 答案 不起作用。所以我们不能将中间的 DataBuffer 转换为字符串,因为缓冲区末尾的字节可能只有部分字节才能构造出有效的字符。
请注意,这会将所有响应的 DataBuffer 加载到内存中,但不像更改整个应用程序的 webClient 的全局设置那样。您可以使用此选项仅在您希望读取完整响应的地方使用,即您可以缩小范围并仅选择此选项,仅在您预期有大量响应时使用。

0

只需将以下代码添加到您的Spring Boot主类中。

@Bean
public WebClient getWebClient() {
    return WebClient.builder()
            .baseUrl("Your_SERVICE_URL")
            .codecs(configurer -> configurer
                      .defaultCodecs()
                      .maxInMemorySize(16 * 1024 * 1024))
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
}

这对我有用。


0
对于那些在添加了各种 bean、定制器和属性后仍无法解决问题的人,请检查是否定义了扩展 WebFluxConfigurationSupport 的 bean。如果定义了,它会禁用相同 bean 的自动配置版本(我的个人经验,Boot 2.7.2),在这个版本中 Spring 加载属性,例如建议的 spring.codec.max-in-memory-size。为使此解决方案生效,您还需要正确配置此属性。
要测试这是否是问题的原因,请暂时删除 WebFluxConfigurationSupport 实现。长期解决方法是使用配置 bean 来覆盖自动配置的 bean 的属性。在我的情况下,WebFluxConfigurer 具有完全相同可用方法,并且是 WebFluxConfigurationSupport 的 drop-in 替换。现在我已成功配置大型 JSON 消息的解码。

0

从Spring Boot 2.7.x开始,我们应该使用以下属性来设置内部使用的响应式ElasticSearch中WebClient的内存大小。

spring.elasticsearch.webclient.max-in-memory-size=512MB


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接