获取:org.springframework.core.io.buffer.DataBufferLimitException:超出缓冲区最大字节数限制:262144

Fre*_*edo 5 spring-boot spring-webflux

我收到了DataBufferLimitException对 HTTP 请求的响应。我在用spring-boot-starter-parent:2.5.0spring-cloud.version:2020.0.2。我几乎已经尝试了此处描述的所有选项(DataBufferLimitException: Exceeded limit on max bytes to buffer webflux error)和此处(configure spring.codec.max-in-memory-size When using ReactiveElasticsearchClient),但没有成功。还有什么我可以尝试的吗?这是我创建网络客户端的代码:

private WebClient buildWebClient(long custId) {
        return WebClient.builder()
                .clientConnector(createWebClientWithTimeout())
                // Add base url to all requests (callers only need to add the path and query params)
                .baseUrl(baseUrl)
                // Filter to add bearer token to auth header before sending request
                .filter((request, next) -> getToken(custId).map(setAuthHeader(request)).flatMap(next::exchange))
                // Filter to send the request, and try again if it has an auth error
                .filter((request, next) -> next.exchange(request).flatMap(clientResponse -> {
                    if (clientResponse.statusCode() == HttpStatus.UNAUTHORIZED) {
                        logger.error("Received 401 Unauthorized from linkedin for request: {} {} with X-LI-UUID header: {}", request.method(), request.url(), 
                                clientResponse.headers().header(LINKEDIN_HEADER));
                        // Retry once if auth failed
                        return clientResponse.bodyToMono(String.class)
                                .doOnNext(err -> logger.warn("Received 401 from linkedin; retrying once. Error body: {}", err))
                                .then(refreshToken(custId).map(setAuthHeader(request)).flatMap(next::exchange));
                    } else if (clientResponse.statusCode().isError()) {
                        logger.error("Received error status code: {} from linkedin for request: {} {} with X-LI-UUID header: {}", clientResponse.statusCode(), request.method(), 
                                request.url(), clientResponse.headers().header(LINKEDIN_HEADER));
                    } else {
                        logger.debug("Received status code: {} from linkedin for request: {} {}", clientResponse.statusCode(), request.method(), request.url());
                    }
                    // If not a 401, just return the response
                    return Mono.just(clientResponse);
                })).build();
    }
Run Code Online (Sandbox Code Playgroud)

spring.codec.max-in-memory-size=16MB添加到属性不起作用,使用ExchangeStrategies显式设置值不起作用,实现WebFluxConfigurer不起作用。这段代码在 spring-boot-starter-parent:2.1.6.RELEASE 下运行良好。关于我下一步可以尝试什么有什么建议吗?

hen*_*nnr 4

Spring Boot 为您预先配置了 WebClienter.Builder,这使得 spring.codec.max-in-memory-size 这样的设置毕竟可以工作。

要使用这个预配置的 WebClient.Builder,您需要将其注入到您的服务中,这与您在上面的示例中所做的不同。您似乎直接使用 WebClient.builder() 方法。

此代码与应用程序属性spring.codec.max-in-memory-size一起可以工作:

@Service
public class Foo(WebClient.Builder injectedPreConfiguredBuilder) {

    private WebClient buildWebClient(long custId) {
            return injectedPreConfiguredBuilder
                    .clientConnector(createWebClientWithTimeout())
                    // Add base url to all requests (callers only need to add the path and query params)
                    .baseUrl(baseUrl)
                    // Filter to add bearer token to auth header before sending request
                    .filter((request, next) -> getToken(custId).map(setAuthHeader(request)).flatMap(next::exchange))
                    // Filter to send the request, and try again if it has an auth error
                    .filter((request, next) -> next.exchange(request).flatMap(clientResponse -> {
                        if (clientResponse.statusCode() == HttpStatus.UNAUTHORIZED) {
                            logger.error("Received 401 Unauthorized from linkedin for request: {} {} with X-LI-UUID header: {}", request.method(), request.url(), 
                                    clientResponse.headers().header(LINKEDIN_HEADER));
                            // Retry once if auth failed
                            return clientResponse.bodyToMono(String.class)
                                    .doOnNext(err -> logger.warn("Received 401 from linkedin; retrying once. Error body: {}", err))
                                    .then(refreshToken(custId).map(setAuthHeader(request)).flatMap(next::exchange));
                        } else if (clientResponse.statusCode().isError()) {
                            logger.error("Received error status code: {} from linkedin for request: {} {} with X-LI-UUID header: {}", clientResponse.statusCode(), request.method(), 
                                    request.url(), clientResponse.headers().header(LINKEDIN_HEADER));
                        } else {
                            logger.debug("Received status code: {} from linkedin for request: {} {}", clientResponse.statusCode(), request.method(), request.url());
                        }
                        // If not a 401, just return the response
                        return Mono.just(clientResponse);
                    })).build();
        }
}

Run Code Online (Sandbox Code Playgroud)

另外,您需要记住,您需要在测试中使用注入/自动装配的 WebClient.Builder 才能使该属性正常工作!

如果您想推出自己的 WebClient.Builder,可以通过编程方式设置缓冲区大小。

科特林示例:

val webClient = WebClient.builder()
    .exchangeStrategies(
    ExchangeStrategies.builder().codecs {
        it.defaultCodecs().maxInMemorySize(1000000) // in bytes
    }.build()
).build()
Run Code Online (Sandbox Code Playgroud)

Java 示例:

WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder().codecs(
                clientCodecConfigurer ->
                clientCodecConfigurer.defaultCodecs().maxInMemorySize(1000000))
        .build())
        .baseUrl("https://stackoverflow.com/posts/68986553/")
        .build();
Run Code Online (Sandbox Code Playgroud)