Spring Cloud Gateway 緩存區(qū)異常問(wèn)題及解決方案
最近在測(cè)試環(huán)境spring cloud gateway突然出現(xiàn)了異常,在這里記錄一下,直接上干貨
1、問(wèn)題背景
測(cè)試環(huán)境spring cloud gateway遇到以下異常
DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144(超出了緩沖區(qū)的最大字節(jié)數(shù)限制)
乍一看,問(wèn)題很簡(jiǎn)單啊,通過(guò)配置加大緩存區(qū)不就行了啊,于是就在application.yml加了以下配置
#將緩存區(qū)設(shè)置為2m spring: codec: max-in-memory-size: 2MB
可是問(wèn)題又出現(xiàn)了,通過(guò)調(diào)試發(fā)現(xiàn)配置的max-in-memory-size在程序啟動(dòng)初始化確實(shí)是生效的。但是有業(yè)務(wù)調(diào)用的時(shí)候,此參數(shù)的接收值為null,maxInMemorySize還是讀取的默認(rèn)值(256K)。
那咋整,只能從源碼入手了。
2、分析源碼過(guò)程
通過(guò)異常日志,可以定位到異常位置
后來(lái)發(fā)現(xiàn)我們自定義的攔截器獲取body的信息是獲取方式,代碼如下
因?yàn)镠andlerStrategies.withDefaults() 是每次都需要重新創(chuàng)建對(duì)象,并非是spring注入的對(duì)象,所以每次獲取的都是默認(rèn)值,導(dǎo)致配置不生效。
3、解決辦法
在我們自定的攔截器中注入ServerCodecConfigurer類,通過(guò)該類獲取配置。這樣獲取到的就是我們?cè)赼pplication.yml中配置的緩存區(qū)配置的字節(jié)數(shù)限制了。
具體代碼:
@Component @Slf4j public class RequestFilter implements GlobalFilter, Ordered { @Override public int getOrder() { return OrderedConstant.HIGHEST_PRECEDENCE; } //手動(dòng)注入ServerCodecConfigurer @Autowired ServerCodecConfigurer codecConfigurer; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); long startTime = System.currentTimeMillis(); try { final Log logDTO = new Log(); ServerHttpRequest request = exchange.getRequest(); // 設(shè)置X-Request-Id AtomicReference<String> requestId = new AtomicReference<>(GenerateIdUtils.requestIdWithUUID()); Consumer<HttpHeaders> httpHeadersConsumer = httpHeaders -> { String headerRequestId = request.getHeaders().getFirst(HeaderConstant.REQUEST_ID); if (!Strings.isNullOrEmpty(headerRequestId)) { requestId.set(headerRequestId); } logDTO.setRequestId(requestId.get()); httpHeaders.set(HeaderConstant.REQUEST_ID, requestId.get()); httpHeaders.set(HeaderConstant.START_TIME_KEY, String.valueOf(startTime)); }; // codecConfigurer.getReaders()獲取pplication.yml中配置的緩存區(qū)配置的字節(jié)數(shù) ServerRequest serverRequest = ServerRequest.create(exchange, codecConfigurer.getReaders()); URI requestUri = request.getURI(); String uriQuery = requestUri.getQuery(); String url = requestUri.getPath() + (!Strings.isNullOrEmpty(uriQuery) ? "?" + uriQuery : ""); HttpHeaders headers = request.getHeaders(); MediaType mediaType = headers.getContentType(); String method = request.getMethodValue().toUpperCase(); // 原始請(qǐng)求體 final AtomicReference<String> requestBody = new AtomicReference<>(); final AtomicBoolean newBody = new AtomicBoolean(false); if (mediaType != null && LogHelper.isUploadFile(mediaType)) { requestBody.set("上傳文件"); } else { if (method.equals("GET")) { if (!Strings.isNullOrEmpty(uriQuery)) { requestBody.set(uriQuery); } } else { newBody.set(true); } } logDTO.setLevel(Log.LEVEL.INFO); logDTO.setRequestUrl(url); logDTO.setRequestBody(requestBody.get()); logDTO.setRequestMethod(method); logDTO.setIp(IpUtils.getClientIp(request)); ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeadersConsumer).build(); ServerWebExchange build = exchange.mutate().request(serverHttpRequest).build(); return build.getSession().flatMap(webSession -> { logDTO.setSessionId(webSession.getId()); if (newBody.get() && headers.getContentLength() > 0) { Mono<String> bodyToMono = serverRequest.bodyToMono(String.class); return bodyToMono.flatMap(reqBody -> { logDTO.setRequestBody(reqBody); // 重寫(xiě)原始請(qǐng)求 ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) { @Override public Flux<DataBuffer> getBody() { NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(reqBody.getBytes()); return Flux.just(bodyDataBuffer); } }; return chain.filter(exchange.mutate() .request(requestDecorator) .build()).then(LogHelper.doRecord(logDTO)); }); } else { return chain.filter(exchange).then(LogHelper.doRecord(logDTO)); } }); } catch (Exception e) { log.error("請(qǐng)求日志打印出現(xiàn)異常", e); return chain.filter(exchange); } } }
到此這篇關(guān)于Spring Cloud Gateway 緩存區(qū)異常的文章就介紹到這了,更多相關(guān)Spring Cloud Gateway 緩存區(qū)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Cloud Gateway層限流實(shí)現(xiàn)過(guò)程
- Spring Cloud Gateway內(nèi)置的斷言和過(guò)濾器作用說(shuō)明
- spring cloud gateway中redis一直打印重連日志問(wèn)題及解決
- Spring?Cloud?Gateway?2.x跨域時(shí)出現(xiàn)重復(fù)Origin的BUG問(wèn)題
- SpringCloud-Gateway網(wǎng)關(guān)的使用實(shí)例教程
- 使用SpringCloud Gateway解決跨域問(wèn)題
- Spring Cloud Gateway組件的三種使用方式實(shí)例詳解
- 一文掌握spring cloud gateway(總結(jié)篇)
相關(guān)文章
springboot集成redis實(shí)現(xiàn)簡(jiǎn)單秒殺系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了springboot集成redis實(shí)現(xiàn)簡(jiǎn)單秒殺系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12如何設(shè)置springboot禁止日志輸出到控制臺(tái)
文章總結(jié):本文主要介紹了SpringBoot項(xiàng)目中使用SLF4J記錄日志時(shí),日志默認(rèn)輸出到控制臺(tái)的原因及解決方法,日志框架如Logback默認(rèn)會(huì)將日志輸出到控制臺(tái),可以通過(guò)`logback-spring.xml`配置文件或配置類來(lái)禁止日志輸出到控制臺(tái),并設(shè)置日志輸出級(jí)別2025-01-01二種jar包制作方法講解(dos打包jar eclipse打包jar文件)
這篇文章主要介紹了二種jar包制作方法講解:dos打包jar和eclipse打包jar文件,大家參考使用吧2013-11-11Java SpringBoot整合Canal實(shí)現(xiàn)數(shù)據(jù)同步方式
本文介紹了如何開(kāi)啟和配置Canal,以及如何在Spring Boot中集成Canal,Canal是一種基于MySQL的數(shù)據(jù)庫(kù)變更解析工具,可以將數(shù)據(jù)庫(kù)的變更事件發(fā)送到Kafka、RocketMQ等消息隊(duì)列中,用于數(shù)據(jù)分析和挖掘2025-02-02spring-data-redis 動(dòng)態(tài)切換數(shù)據(jù)源的方法
最近遇到了一個(gè)麻煩的需求,我們需要一個(gè)微服務(wù)應(yīng)用同時(shí)訪問(wèn)兩個(gè)不同的 Redis 集群,一般情況下我們會(huì)怎么處理呢,下面通過(guò)場(chǎng)景分析給大家介紹spring-data-redis 動(dòng)態(tài)切換數(shù)據(jù)源的方法,感興趣的朋友一起看看吧2021-08-08詳解IDEA中類加載器調(diào)用getResourceAsStream()方法需注意的問(wèn)題
這篇文章主要介紹了詳解IDEA中類加載器調(diào)用getResourceAsStream()方法需注意的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02加速spring/springboot應(yīng)用啟動(dòng)速度詳解
這篇文章主要介紹了加速spring/springboot應(yīng)用啟動(dòng)速度詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Linux中Java開(kāi)發(fā)常用軟件安裝方法總結(jié)
這篇文章主要介紹了Linux中Java開(kāi)發(fā)常用軟件安裝方法總結(jié),需要的朋友可以參考下2020-02-02