1. 引言
在本教程中,我們將探討在 Spring Webflux 應用程序中可能出現的 DataBufferLimitException 的原因。然後,我們將研究解決這些問題的各種方法。
2. 理解問題
在開始尋找解決方案之前,首先要理解問題。
2.1. 什麼是 <em DataBufferLimitException</em>?
Spring WebFlux 通過限制在編解碼器中對數據的內存內緩衝,以避免應用程序內存問題。<strong>默認情況下,此配置設置為 262,144 字節</strong>。當這不足以滿足我們的用例時,我們將會遇到<em DataBufferLimitException`。
2.2. 什麼是 編解碼器 (Codec)?
<em >spring-web</em> 和 <em >spring-core</em> 模塊提供通過非阻塞 I/O 和反應式流背壓,對字節內容進行序列化和反序列化到和從更高層次的對象之間的支持。 編解碼器 提供了一種替代 Java 序列化的方法。 其中一個 優勢 是,通常情況下,對象不需要實現 <em >Serializable</em>。
3. 服務器端
讓我們首先從服務器端視角來看 DataBufferLimitException 的表現。
3.1. 模擬問題
讓我們嘗試向我們的 Spring Webflux 服務器應用程序發送一個 390 KB 大小的 JSON 負載,以創建該異常。我們將使用 curl 命令向我們的服務器發送一個 POST 請求:
curl --location --request POST 'http://localhost:8080/1.0/process' \
--header 'Content-Type: application/json' \
--data-binary '@/tmp/390KB.json'如我們所見,DataBufferLimitException 異常已被拋出:
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:99) ~[spring-core-5.3.23.jar:5.3.23]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ HTTP POST "/1.0/process" [ExceptionHandlingWebHandler]3.2. 解決方案
我們可以使用 <em >WebFluxConfigurer</em> 接口來配置相同的閾值。為此,我們將添加一個新的配置類,WebFluxConfiguration。
@Configuration
public class WebFluxConfiguration implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(500 * 1024);
}
}我們還需要更新應用程序的屬性:
spring:
codec:
max-in-memory-size: 500KB4. 客户端
現在,讓我們轉向關注客户端行為。
4.1. 模擬問題
我們將嘗試使用 Webflux 的 WebClient 模擬相同行為。 創建一個處理程序,該處理程序向服務器發送包含 390 KB 負載的數據:
public Mono<Users> fetch() {
return webClient
.post()
.uri("/1.0/process")
.body(BodyInserters.fromPublisher(readRequestBody(), Users.class))
.exchangeToMono(clientResponse -> clientResponse.bodyToMono(Users.class));
}我們再次看到相同的異常被拋出,但這次由於 webClient 嘗試發送超過允許的較大負載所導致:
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:99) ~[spring-core-5.3.23.jar:5.3.23]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ Body from POST http://localhost:8080/1.0/process [DefaultClientResponse]
*__checkpoint ⇢ Handler com.baeldung.spring.reactive.springreactiveexceptions.handler.TriggerHandler@428eedd9 [DispatcherHandler]
*__checkpoint ⇢ HTTP POST "/1.0/trigger" [ExceptionHandlingWebHandler]4.2. 解決方案
我們還提供了一種編程方式來配置 Web 客户端以實現這一目標。讓我們創建一個帶有以下配置的 <em >WebClient</em>:
@Bean("progWebClient")
public WebClient getProgSelfWebClient() {
return WebClient
.builder()
.baseUrl(host)
.exchangeStrategies(ExchangeStrategies
.builder()
.codecs(codecs -> codecs
.defaultCodecs()
.maxInMemorySize(500 * 1024))
.build())
.build();
}我們還需要更新應用程序的屬性:
spring:
codec:
max-in-memory-size: 500KB有了以上配置,我們現在應該能夠從我們的應用程序中發送大於 500KB 的負載。需要注意的是,此配置會應用於整個應用程序,包括所有 Web 客户端和服務器本身。
因此,如果我們希望僅針對特定 Web 客户端配置此限制,那麼這可能不是一個理想的解決方案。此外,這種方法還存在一些限制。用於創建 WebClients 的構建器必須像下面這樣由 Spring 自動注入:
@Bean("webClient")
public WebClient getSelfWebClient(WebClient.Builder builder) {
return builder.baseUrl(host).build();
}5. 結論
在本文中,我們瞭解了什麼是 <em >DataBufferLimitException</em>,並探討了在服務器端和客户端上如何解決這些問題。我們針對兩者都採用了兩種方法,即基於屬性配置和編程方式。我們希望這個異常不再給您帶來麻煩。