Spring DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

文章目录

  • Spring DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
    • 前言
    • 问题分析
    • 问题解决过程
      • 通过配置参数加大缓冲区
      • 通过配置类加大缓冲区
      • 限制接口返回JSON的大小
      • 检查网关的拦截器(Filter)是否操作了HTTP body
    • 问题解决结果
    • 另类解决方法:Hack一个AbstractDataBufferDecoder类

Spring DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

前言

最近在项目中遇到了两次org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

问题1:REST API接口返回JSON超过256K时报错;

问题2:下载文件接口(返回二进制文件流,Content-Type为application/octet-stream)文件超过256K时报错。

Spring版本:

  • Spring Boot 2.2.2.RELEASE
  • Spring Core 5.2.2.RELEASE

问题分析

项目基于Spring Cloud Gateway来开发了API网关,上面的错误都发生在API网关。

从日志来看是典型的缓冲区溢出错误。

对问题1,只要加大缓冲区,或者限制返回JSON的大小就可以解决。

对问题2,写文件流的方式,按道理写入缓冲区的数据会被消费走,不应该出现缓冲区溢出错误。

问题解决过程

通过配置参数加大缓冲区

默认的缓冲区为256K,可以通过配置spring.codec.max-in-memory-size加大缓冲区:

spring:
  codec:
    max-in-memory-size: 2MB

关于该参数说明:

spring.codec.max-in-memory-size:

Limit on the number of bytes that can be buffered whenever the input stream needs to be aggregated. This applies only to the auto-configured WebFlux server and WebClient instances. By default this is not set, in which case individual codec defaults apply. Most codecs are limited to 256K by default.

不幸的是,该参数在Spring Boot 2.2.2.RELEASE 中不生效,在其它Spring Boot版本中可能生效。

参见:

  • https://github.com/spring-projects/spring-boot/issues/18828
  • https://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/appendix-application-properties.html
  • https://docs.spring.io/autorepo/docs/spring-boot/2.2.2.RELEASE/reference/html/appendix-application-properties.html

通过配置类加大缓冲区

增加一个配置类来加大缓冲区:

@Configuration
@EnableWebFlux
public class WebFluxWebConfig implements WebFluxConfigurer {
    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024);
    }
}

不幸的是,该配置类在Spring Boot 2.2.2.RELEASE 中不生效,在其它Spring Boot版本中可能生效。

参见:

  • https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux-config-message-codecs

限制接口返回JSON的大小

通过Jackson的@JsonInclude(JsonInclude.Include.NON_NULL) 注解在接口返回的JSON中过滤掉为 null的字段,以限制接口返回JSON的大小。

检查网关的拦截器(Filter)是否操作了HTTP body

如果网关的拦截器(Filter)中操作了HTTP body,也可能会出现DataBufferLimitException的问题。

问题解决结果

对于问题一,由于不能改变项目中使用的Spring Boot的版本,无法采用加大缓冲区的方式,最终通过限制接口返回JSON的大小来解决。

对于问题二,对Content-Type为application/octet-stream时(返回二进制流时),不在网关的拦截器(Filter)中操作HTTP body来避免缓冲区溢出错误。

另类解决方法:Hack一个AbstractDataBufferDecoder类

查看Spring Core 5.2.2.RELEASE的AbstractDataBufferDecoder类,发现虽然maxInMemorySize的默认值是262144,但是外部是可以调用它的setMaxInMemorySize()方法来设值的。但是不知道什么原因,设值就是不生效。

public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
    private int maxInMemorySize = 262144;
	
	...
	
    public void setMaxInMemorySize(int byteCount) {
        this.maxInMemorySize = byteCount;
    }

    public int getMaxInMemorySize() {
        return this.maxInMemorySize;
    }

    ...
}

在不改变Spring版本的情况下,可以hack一个相同包路径的AbstractDataBufferDecoder类,将maxInMemorySize值调大。
比如,调大到2M:

private int maxInMemorySize = 2 * 1024 * 1024;

你可能感兴趣的:(SpringBoot)