DataBufferLimitException:超出缓冲 webflux 错误的最大字节数限制

tav*_*ced 39 java spring webclient spring-webflux

在发送文件时,我收到一个字节数组。我总是遇到 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
Run Code Online (Sandbox Code Playgroud)

你现在如何在 webflux 中解决这个问题?

Gur*_*Cse 57

这为我工作

  1. 在您的配置类或主 Springbootapplication 类之一中创建一个 bean

    @Bean
    public WebClient getWebClientBuilder(){
        return   WebClient.builder().exchangeStrategies(ExchangeStrategies.builder()
                .codecs(configurer -> configurer
                          .defaultCodecs()
                          .maxInMemorySize(16 * 1024 * 1024))
                        .build())
                      .build();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 接下来转到您想要使用 webclient 的所需类

      @RestController / @Bean/ @Service
       public class PaySharpGatewayController {
            @Autowired
            WebClient webClient;
    
            public void test(){
             String out = webClient
                          .get()
                          .uri("end point of an API")
                          .retrieve()
                          .bodyToMono(String.class)
                         .block();
    
             sysout(out)
            }
    
    Run Code Online (Sandbox Code Playgroud)

  • 不知道为什么,这是唯一适用于 WebFlux 2.3.2.RELEASE 的解决方案 (2认同)

Dav*_*vid 36

我想这个问题是关于在 Spring Boot 中添加一个新的 spring.codec.max-in-memory-size 配置属性。将其添加到如下属性中:

spring:
  codec:
    max-in-memory-size: 10MB
Run Code Online (Sandbox Code Playgroud)

  • 我在我的 Spring Boot 应用程序配置中使用它,但是它没有帮助。 (8认同)
  • @mareck_ste 嗨!也许您正在使用一些覆盖此选项的自定义配置。例如,您有 WebClient 配置,因此只需在 WebClientBuilder.exchangeStrategies() 中设置“maxInMemorySize”属性 (4认同)
  • 如果上面基于配置的解决方案不起作用 - 以下可能会解释原因 - 您需要使用预先配置的 Spring WebClient.Builder 而不是创建自己的 https://github.com/spring-projects/spring-boot /问题/27836 (4认同)
  • @mareck_ste 确实,我对 spring-boot-starter-webflux 2.3.5-RELEASE 也有同样的想法。看看这个[优秀答案](/sf/answers/4157441571/) (3认同)

小智 27

这是摆脱异常的官方方法(请参阅文档):

webTestClient.mutate()
  .codecs(configurer -> configurer
          .defaultCodecs()
          .maxInMemorySize(16 * 1024 * 1024))
  .build().get()
  .uri("/u/r/l")
  .exchange()
  .expectStatus()
  .isOk()
Run Code Online (Sandbox Code Playgroud)


Dat*_*eek 15

对于一个简单的 RestController,我收到了这个错误(我发布了一个大的 json 字符串)。

这是我如何成功更改 maxInMemorySize

import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;

@Configuration
public class WebfluxConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/swagger-ui.html**")
            .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024);
    }
}
Run Code Online (Sandbox Code Playgroud)

这出奇地难找

  • 为什么要显示 addResourceHandlers 方法?它与问题有某种关系吗? (5认同)

小智 13

spring boot配置文件中设置最大字节(以兆字节为单位),如下所示:

spring.codec.max-in-memory-size=20MB
Run Code Online (Sandbox Code Playgroud)

  • 如果这不起作用,这可能就是为什么 https://github.com/spring-projects/spring-boot/issues/27836 (2认同)

Tir*_*res 9

您可以流式传输,而不是立即检索数据:

Mono<String> string = webClient.get()
    .uri("end point of an API")
    .retrieve()
    .bodyToFlux(DataBuffer.class)
    .map(buffer -> {
        String string = buffer.toString(Charset.forName("UTF-8"));
        DataBufferUtils.release(buffer);
        return string;
    });
Run Code Online (Sandbox Code Playgroud)

或者转换为流:

    .map(b -> b.asInputStream(true))
    .reduce(SequenceInputStream::new)
    .map(stream -> {
        // consume stream
        stream.close();
        return string;
    });
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,您不想真正聚合流,而不是直接处理它。需要在内存中加载大量数据主要是改变方法的一种标志。JSON 和 XML 解析器具有流接口。

  • “缓冲区”在哪里定义? (2认同)
  • 您实际上测量了总体内存占用量吗?即,即使在释放数据缓冲区之后,除非您消耗最终流,否则内存仍然会堆积,因为您正在使用归约,直到收到最后一个字节。所以,我不确定使用这种方法是否会有任何优势 (2认同)
  • 这个想法是这里所有答案中最好的一个。在所提供的示例代码中,我唯一不喜欢的是对“DataBufferUtils.release(buffer)”的调用。闻起来像手动内存管理,这与一般的 Java 非常相悖。 (2认同)

小智 7

这对我有用

val exchangeStrategies = ExchangeStrategies.builder()
                .codecs { configurer: ClientCodecConfigurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024) }.build()
        return WebClient.builder().exchangeStrategies(exchangeStrategies).build()
Run Code Online (Sandbox Code Playgroud)