问题:org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:98)
at org.springframework.core.io.buffer.LimitedDataBufferList.updateCount(LimitedDataBufferList.java:91)
at org.springframework.core.io.buffer.LimitedDataBufferList.add(LimitedDataBufferList.java:57)
at reactor.core.publisher.MonoCollect$CollectSubscriber.onNext(MonoCollect.java:118)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
解决方案:
spring:
codec:
max-in-memory-size: 50MB
@Component
@Slf4j
public class GwReadBodyRoutePredicateFactory extends
AbstractRoutePredicateFactory<GwReadBodyRoutePredicateFactory.Config> {
private static final String TEST_ATTRIBUTE = "read_body_predicate_test_attribute";
private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
private final List<HttpMessageReader<?>> messageReaders;
/**
* 获取Spring配置,解决最大body问题
*/
@Autowired
ServerCodecConfigurer codecConfigurer;
public GwReadBodyRoutePredicateFactory() {
super(GwReadBodyRoutePredicateFactory.Config.class);
this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
}
public GwReadBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
super(GwReadBodyRoutePredicateFactory.Config.class);
this.messageReaders = messageReaders;
}
@Override
@SuppressWarnings("unchecked")
public AsyncPredicate<ServerWebExchange> applyAsync(
GwReadBodyRoutePredicateFactory.Config config
) {
return new AsyncPredicate<ServerWebExchange>() {
@Override
public Publisher<Boolean> apply(ServerWebExchange exchange) {
Class inClass = config.getInClass();
Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
Mono<?> modifiedBody;
// We can only read the body from the request once, once that happens if
// we try to read the body again an exception will be thrown. The below
// if/else caches the body object as a request attribute in the
// ServerWebExchange so if this filter is run more than once (due to more
// than one route using it) we do not try to read the request body
// multiple times
if (cachedBody != null) {
try {
boolean test = config.predicate.test(cachedBody);
exchange.getAttributes().put(TEST_ATTRIBUTE, test);
return Mono.just(test);
} catch (ClassCastException e) {
if (log.isDebugEnabled()) {
log.debug("Predicate test failed because class in predicate "
+ "does not match the cached body object", e);
}
}
return Mono.just(false);
} else {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
(serverHttpRequest) -> ServerRequest.create(
exchange.mutate().request(serverHttpRequest).build(), codecConfigurer.getReaders())
.bodyToMono(inClass)
.doOnNext(objectValue -> exchange.getAttributes()
.put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue))
.map(objectValue -> config.getPredicate().test(objectValue))
.thenReturn(true));
}
}
@Override
public String toString() {
return String.format("ReadBody: %s", config.getInClass());
}
};
}
@Override
@SuppressWarnings("unchecked")
public Predicate<ServerWebExchange> apply(
GwReadBodyRoutePredicateFactory.Config config
) {
throw new UnsupportedOperationException("GwReadBodyPredicateFactory is only async.");
}
public static class Config {
private Class inClass;
private Predicate predicate;
private Map<String, Object> hints;
public Class getInClass() {
return inClass;
}
public GwReadBodyRoutePredicateFactory.Config setInClass(Class inClass) {
this.inClass = inClass;
return this;
}
public Predicate getPredicate() {
return predicate;
}
public GwReadBodyRoutePredicateFactory.Config setPredicate(Predicate predicate) {
this.predicate = predicate;
return this;
}
public <T> GwReadBodyRoutePredicateFactory.Config setPredicate(Class<T> inClass, Predicate<T> predicate) {
setInClass(inClass);
this.predicate = predicate;
return this;
}
public Map<String, Object> getHints() {
return hints;
}
public GwReadBodyRoutePredicateFactory.Config setHints(Map<String, Object> hints) {
this.hints = hints;
return this;
}
}
}