一、描述 最近在批量上傳文件時網關出現了異常,後面發現上傳大文件也會出現文件超過256發生異常,異常信息如下: org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to bu ...
一、描述
最近在批量上傳文件時網關出現了異常,後面發現上傳大文件也會出現文件超過256發生異常,異常信息如下:
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)
二、解決
1. 在配置文件中配置 max-in-memory-size: 1024MB
spring:
codec:
max-in-memory-size: 1024MB
結果:無效
2. 配置類中加大緩存
@Configuration
@EnableWebFlux
public class WebFluxWebConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024);
}
}
結果:無效
3. 對網關過濾器或攔截器RequestBodyRoutePredicateFactory的操作
原代碼:
public class RequestBodyRoutePredicateFactory
extends AbstractRoutePredicateFactory<RequestBodyRoutePredicateFactory.Config> {
protected static final Log LOGGER = LogFactory.getLog(RequestBodyRoutePredicateFactory.class);
private final List<HttpMessageReader<?>> messageReaders;
public RequestBodyRoutePredicateFactory() {
super(RequestBodyRoutePredicateFactory.Config.class);
this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
}
public RequestBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
super(RequestBodyRoutePredicateFactory.Config.class);
this.messageReaders = messageReaders;
}
public static final String REQUEST_BODY_ATTR = "requestBodyAttr";
@Override
public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
return exchange -> {
if (!"POST".equals(exchange.getRequest().getMethodValue()) && !"PUT".equals(exchange.getRequest().getMethodValue())) {
return Mono.just(true);
}
Object cachedBody = exchange.getAttribute(REQUEST_BODY_ATTR);
if (cachedBody != null) {
try {
return Mono.just(true);
} catch (ClassCastException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Predicate test failed because class in predicate does not match the cached body object",
e);
}
}
return Mono.just(true);
} else {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> ServerRequest.create(exchange.mutate().request(serverHttpRequest).build(),
//this.messageReaders 的預設緩存還是256k
this.messageReaders).bodyToMono(String.class).defaultIfEmpty("").doOnNext((objectValue) -> {
if (StringUtils.isBlank(objectValue)) {
exchange.getAttributes().put(REQUEST_BODY_ATTR, JSON.toJSONString(exchange.getRequest().getQueryParams()));
} else {
exchange.getAttributes().put(REQUEST_BODY_ATTR, objectValue);
}
}).map((objectValue) -> true));
}
};
}
....
}
原因
:原代碼中獲取body後,重新創建ServerRequest時,org.springframework.core.io.buffer.LimitedDataBufferList中判斷接收數據大小超過制,org.springframework.core.codec.AbstractDataBufferDecoder中的預設262144。
具體可參考DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
解決辦法
:註入ServerCodecConfigurer,使用ServerCodecConfigurer.getReaders()獲取相關配置。
public class RequestBodyRoutePredicateFactory
extends AbstractRoutePredicateFactory<RequestBodyRoutePredicateFactory.Config> {
protected static final Log LOGGER = LogFactory.getLog(RequestBodyRoutePredicateFactory.class);
//註入spring.codec.max-in-memory-size
@Autowired
ServerCodecConfigurer codecConfigurer;
private final List<HttpMessageReader<?>> messageReaders;
public RequestBodyRoutePredicateFactory() {
super(RequestBodyRoutePredicateFactory.Config.class);
this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
}
public RequestBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
super(RequestBodyRoutePredicateFactory.Config.class);
this.messageReaders = messageReaders;
}
public static final String REQUEST_BODY_ATTR = "requestBodyAttr";
@Override
public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
return exchange -> {
if (!"POST".equals(exchange.getRequest().getMethodValue()) && !"PUT".equals(exchange.getRequest().getMethodValue())) {
return Mono.just(true);
}
Object cachedBody = exchange.getAttribute(REQUEST_BODY_ATTR);
if (cachedBody != null) {
try {
return Mono.just(true);
} catch (ClassCastException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Predicate test failed because class in predicate does not match the cached body object",
e);
}
}
return Mono.just(true);
} else {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) ->
//codecConfigurer.getReaders(),來獲取spring.codec.max-in-memory-size的配置
ServerRequest.create(exchange.mutate().request(serverHttpRequest).build(),codecConfigurer.getReaders()).bodyToMono(String.class).defaultIfEmpty("").doOnNext((objectValue) -> {
if (StringUtils.isBlank(objectValue)) {
exchange.getAttributes().put(REQUEST_BODY_ATTR, JSON.toJSONString(exchange.getRequest().getQueryParams()));
} else {
exchange.getAttributes().put(REQUEST_BODY_ATTR, objectValue);
}
}).map((objectValue) -> true));
}
};
}
.....
}
結果:成功