BUG - Gateway: Exceeded limit on max bytes to buffer : 262144

87 阅读1分钟

BUG - Gateway: Exceeded limit on max bytes to buffer : 262144

总结

0. 配置最大限制

首先实现 WebFluxConfigurer 接口, 并重写 configureHttpMessageCodecs 方法

设置 ServerCodecConfigurer 中 defaultCodecs 的 maxInMemorySize, 这相当于解开最大限制

根据不同的使用情况有不同的处理方式

1. 默认 CacheRequestBodyGatewayFilterFactory

如果使用的是默认 CacheRequestBodyGatewayFilterFactory, 配置好就应该就可以了(没有测试过)

2. 自定义 Filter

如果使用的是自定义的 filter

检查是否使用了 HandlerStrategies.withDefaults().messageReaders() 语句

2.1 如果使用了该语句

将配置的 ServerCodecConfigurer 进行注入 (@Resource, @Autowired) 都可以

然后将 HandlerStrategies.withDefaults().messageReaders() 替换为 serverCodecConfigurer.getReaders() 即可

2.2 如果没有使用

我也不知道怎么办了, 求大神指教, (TwT)

代码

配置


package cn.moquan.gateway.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.config.WebFluxConfigurer;

@Configuration
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(10 * 1024 * 1024);
    }

}

使用


package cn.moquan.gateway.filter.global;

import cn.moquan.gateway.tool.RequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.function.Function;

public class CopyRequestBodyGlobalFilter implements GlobalFilter, Ordered {

    @Resource
    private ServerCodecConfigurer serverCodecConfigurer;

    private static final Logger log = LoggerFactory.getLogger(CopyRequestBodyGlobalFilter.class);

    /**
     * 参考实现:
     * org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory
     *
     * @param exchange the current server exchange
     * @param chain    provides a way to delegate to the next filter
     */
    @Override
    @SuppressWarnings("unchecked")
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.debug("go through copy request body global filter.");

        if (RequestUtil.isGetRequest(exchange) || !RequestUtil.contextTypeIsJson(exchange)) {
            // 非 json 请求直接放行
            return chain.filter(exchange);
        }

        /////////////////////////////////////////////////////////////       就这里 ↓
        ServerRequest serverRequest = ServerRequest.create(exchange, serverCodecConfigurer.getReaders());
        Mono<String> requestBodyStrMono = serverRequest.bodyToMono(String.class)
                .flatMap(Mono::just);

        BodyInserter bodyInserter = BodyInserters.fromPublisher(requestBodyStrMono, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());
        headers.remove(HttpHeaders.CONTENT_LENGTH);

        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
        return bodyInserter.insert(outputMessage, new BodyInserterContext())
                .then(Mono.defer(() -> {
                    ServerHttpRequest decorator = RequestUtil.decorateServerWebExchange(exchange, headers, outputMessage);
                    return chain.filter(exchange.mutate().request(decorator).build());
                })).onErrorResume((Function<Throwable, Mono<Void>>) throwable ->
                        RequestUtil.releaseOutputMessageBodyDataBuffer(exchange, outputMessage, throwable)
                );
    }

    @Override
    public int getOrder() {
        return 0;
    }

}