如何解決 Spring Webflux DataBufferLimitException
一、簡介
在本教程中,我們將探討為什麼會在 Spring Webflux 應用程序中看到DataBufferLimitException
。然後,我們將看看我們可以解決相同問題的各種方法。
2. 理解問題
在跳到解決方案之前,讓我們先了解問題。
2.1。什麼是DataBufferLimitException?
Spring WebFlux 限制了編解碼器中內存中數據的緩衝,以避免應用程序內存問題。默認情況下,它被配置為 262,144 字節。當這對我們的用例來說還不夠時,我們將得到DataBufferLimitException
。
2.2.什麼是Codec
?
spring-web
和spring-core
模塊支持通過具有反應流背壓的非阻塞 I/O 對更高級別對象的字節內容進行序列化和反序列化。 [Codecs](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-codecs)
提供了 Java 序列化的替代方案。一個優點是,通常,對像不需要實現Serializable.
3.服務器端
讓我們首先從服務器的角度看一下DataBufferLimitException
是如何發揮作用的。
3.1。重現問題
讓我們嘗試將大小為 390 KB 的 JSON 有效負載發送到我們的 Spring Webflux 服務器應用程序以創建異常。我們將使用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.通過屬性解決方案
最簡單的解決方案是配置應用程序屬性spring.codec.max-in-memory-size
。讓我們將以下內容添加到我們的application.yaml
文件中:
spring:
codec:
max-in-memory-size: 500KB
有了這個,我們現在應該能夠在我們的應用程序中緩衝大於 500 KB 的有效負載。
3.3.通過代碼解決
或者,我們可以使用WebFluxConfigurer
接口來配置相同的閾值。為此,我們將添加一個新的配置類WebFluxConfiguration:
@Configuration
public class WebFluxConfiguration implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(500 * 1024);
}
}
這種方法也將為我們提供相同的結果。
4.客戶端
現在讓我們換個角度來看看客戶端的行為。
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.[email protected]428eedd9 [DispatcherHandler]
*__checkpoint ⇢ HTTP POST "/1.0/trigger" [ExceptionHandlingWebHandler]
4.2.通過屬性解決方案
同樣,最簡單的解決方案是配置應用程序屬性spring.codec.max-in-memory-size
。讓我們將以下內容添加到我們的application.yaml
文件中:
spring:
codec:
max-in-memory-size: 500KB
有了這個,我們現在應該能夠從我們的應用程序發送大於 500 KB 的有效負載。值得注意的是,此配置應用於整個應用程序,這意味著所有 Web 客戶端 和服務器本身。
因此,如果我們只想為特定的 Web 客戶端配置此限制,那麼這將不是一個理想的解決方案。此外,這種方法有一個警告。用於創建WebClients
的構建器必須由 Spring 自動連接,如下所示:
@Bean("webClient")
public WebClient getSelfWebClient(WebClient.Builder builder) {
return builder.baseUrl(host).build();
}
4.3.通過代碼解決
我們還有一種編程方式來配置 Web 客戶端以實現這一目標。讓我們使用以下配置創建一個WebClient
:
@Bean("progWebClient")
public WebClient getProgSelfWebClient() {
return WebClient
.builder()
.baseUrl(host)
.exchangeStrategies(ExchangeStrategies
.builder()
.codecs(codecs -> codecs
.defaultCodecs()
.maxInMemorySize(500 * 1024))
.build())
.build();
}
有了這個,我們現在應該能夠使用我們的 Web 客戶端成功發送大於 500 KB 的有效負載。
5. 結論
在本文中,我們了解了DataBufferLimitException
是什麼,並研究瞭如何在服務器端和客戶端修復它們。我們研究了兩種方法,首先是基於屬性配置,其次是編程。我們希望這個例外不會再給您帶來麻煩。
與往常一樣,完整的代碼可以在 GitHub 上找到。