0


Spring Cloud Gateway 缓存区异常

最近在测试环境spring cloud gateway突然出现了异常,在这里记录一下,直接上干货

1、问题背景

测试环境spring cloud gateway遇到以下异常

DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144(超出了缓冲区的最大字节数限制)

乍一看,问题很简单啊,通过配置加大缓存区不就行了啊,于是就在application.yml加了以下配置

  1. #将缓存区设置为2m
  2. spring:
  3. codec:
  4. max-in-memory-size: 2MB

可是问题又出现了,通过调试发现配置的max-in-memory-size在程序启动初始化确实是生效的。但是有业务调用的时候,此参数的接收值为null,maxInMemorySize还是读取的默认值(256K)。

那咋整,只能从源码入手了。

2、分析源码过程

通过异常日志,可以定位到异常位置

后来发现我们自定义的拦截器获取body的信息是获取方式,代码如下

因为HandlerStrategies.withDefaults() 是每次都需要重新创建对象,并非是spring注入的对象,所以每次获取的都是默认值,导致配置不生效。

3、解决办法

在我们自定的拦截器中注入ServerCodecConfigurer类,通过该类获取配置。这样获取到的就是我们在application.yml中配置的缓存区配置的字节数限制了。

具体代码:

  1. @Component
  2. @Slf4j
  3. public class RequestFilter implements GlobalFilter, Ordered {
  4. @Override
  5. public int getOrder() {
  6. return OrderedConstant.HIGHEST_PRECEDENCE;
  7. }
  8. //手动注入ServerCodecConfigurer
  9. @Autowired
  10. ServerCodecConfigurer codecConfigurer;
  11. @Override
  12. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  13. StopWatch stopWatch = new StopWatch();
  14. stopWatch.start();
  15. long startTime = System.currentTimeMillis();
  16. try {
  17. final Log logDTO = new Log();
  18. ServerHttpRequest request = exchange.getRequest();
  19. // 设置X-Request-Id
  20. AtomicReference<String> requestId = new AtomicReference<>(GenerateIdUtils.requestIdWithUUID());
  21. Consumer<HttpHeaders> httpHeadersConsumer = httpHeaders -> {
  22. String headerRequestId = request.getHeaders().getFirst(HeaderConstant.REQUEST_ID);
  23. if (!Strings.isNullOrEmpty(headerRequestId)) {
  24. requestId.set(headerRequestId);
  25. }
  26. logDTO.setRequestId(requestId.get());
  27. httpHeaders.set(HeaderConstant.REQUEST_ID, requestId.get());
  28. httpHeaders.set(HeaderConstant.START_TIME_KEY, String.valueOf(startTime));
  29. };
  30. // codecConfigurer.getReaders()获取pplication.yml中配置的缓存区配置的字节数
  31. ServerRequest serverRequest = ServerRequest.create(exchange,
  32. codecConfigurer.getReaders());
  33. URI requestUri = request.getURI();
  34. String uriQuery = requestUri.getQuery();
  35. String url = requestUri.getPath() + (!Strings.isNullOrEmpty(uriQuery) ? "?" + uriQuery : "");
  36. HttpHeaders headers = request.getHeaders();
  37. MediaType mediaType = headers.getContentType();
  38. String method = request.getMethodValue().toUpperCase();
  39. // 原始请求体
  40. final AtomicReference<String> requestBody = new AtomicReference<>();
  41. final AtomicBoolean newBody = new AtomicBoolean(false);
  42. if (mediaType != null && LogHelper.isUploadFile(mediaType)) {
  43. requestBody.set("上传文件");
  44. } else {
  45. if (method.equals("GET")) {
  46. if (!Strings.isNullOrEmpty(uriQuery)) {
  47. requestBody.set(uriQuery);
  48. }
  49. } else {
  50. newBody.set(true);
  51. }
  52. }
  53. logDTO.setLevel(Log.LEVEL.INFO);
  54. logDTO.setRequestUrl(url);
  55. logDTO.setRequestBody(requestBody.get());
  56. logDTO.setRequestMethod(method);
  57. logDTO.setIp(IpUtils.getClientIp(request));
  58. ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeadersConsumer).build();
  59. ServerWebExchange build = exchange.mutate().request(serverHttpRequest).build();
  60. return build.getSession().flatMap(webSession -> {
  61. logDTO.setSessionId(webSession.getId());
  62. if (newBody.get() && headers.getContentLength() > 0) {
  63. Mono<String> bodyToMono = serverRequest.bodyToMono(String.class);
  64. return bodyToMono.flatMap(reqBody -> {
  65. logDTO.setRequestBody(reqBody);
  66. // 重写原始请求
  67. ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
  68. @Override
  69. public Flux<DataBuffer> getBody() {
  70. NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
  71. DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(reqBody.getBytes());
  72. return Flux.just(bodyDataBuffer);
  73. }
  74. };
  75. return chain.filter(exchange.mutate()
  76. .request(requestDecorator)
  77. .build()).then(LogHelper.doRecord(logDTO));
  78. });
  79. } else {
  80. return chain.filter(exchange).then(LogHelper.doRecord(logDTO));
  81. }
  82. });
  83. } catch (Exception e) {
  84. log.error("请求日志打印出现异常", e);
  85. return chain.filter(exchange);
  86. }
  87. }
  88. }
标签: gateway 网络

本文转载自: https://blog.csdn.net/weixin_44543482/article/details/135288499
版权归原作者 小徐很努力 所有, 如有侵权,请联系我们删除。

“Spring Cloud Gateway 缓存区异常”的评论:

还没有评论