批量上传文件或者上传大文件时 gateWay报错DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
一、描述
最近在批量上传文件时网关出现了异常,后面发现上传大文件也会出现文件超过256发生异常,异常信息如下:
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144 	at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:101)
二、解决
1. 在配置文件中配置 max-in-memory-size: 1024MB
spring:
  codec:
    max-in-memory-size: 1024MB
结果:无效
2. 配置类中加大缓存
@Configuration
@EnableWebFlux
public class WebFluxWebConfig implements WebFluxConfigurer {
    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024);
    }
}
结果:无效
3. 对网关过滤器或拦截器RequestBodyRoutePredicateFactory的操作
原代码:
public class RequestBodyRoutePredicateFactory
        extends AbstractRoutePredicateFactory<RequestBodyRoutePredicateFactory.Config> {
    protected static final Log LOGGER = LogFactory.getLog(RequestBodyRoutePredicateFactory.class);
    private final List<HttpMessageReader<?>> messageReaders;
    public RequestBodyRoutePredicateFactory() {
        super(RequestBodyRoutePredicateFactory.Config.class);
        this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
    }
    public RequestBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
        super(RequestBodyRoutePredicateFactory.Config.class);
        this.messageReaders = messageReaders;
    }
    public static final String REQUEST_BODY_ATTR = "requestBodyAttr";
    @Override
    public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
        return exchange -> {
            if (!"POST".equals(exchange.getRequest().getMethodValue()) && !"PUT".equals(exchange.getRequest().getMethodValue())) {
                return Mono.just(true);
            }
            Object cachedBody = exchange.getAttribute(REQUEST_BODY_ATTR);
            if (cachedBody != null) {
                try {
                    return Mono.just(true);
                } catch (ClassCastException e) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Predicate test failed because class in predicate does not match the cached body object",
                                e);
                    }
                }
                return Mono.just(true);
            } else {
                return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> ServerRequest.create(exchange.mutate().request(serverHttpRequest).build(),
//this.messageReaders 的默认缓存还是256k
this.messageReaders).bodyToMono(String.class).defaultIfEmpty("").doOnNext((objectValue) -> {
                    if (StringUtils.isBlank(objectValue)) {
                        exchange.getAttributes().put(REQUEST_BODY_ATTR, JSON.toJSONString(exchange.getRequest().getQueryParams()));
                    } else {
                        exchange.getAttributes().put(REQUEST_BODY_ATTR, objectValue);
                    }
                }).map((objectValue) -> true));
            }
        };
    }
  ....
}
原因:原代码中获取body后,重新创建ServerRequest时,org.springframework.core.io.buffer.LimitedDataBufferList中判断接收数据大小超过制,org.springframework.core.codec.AbstractDataBufferDecoder中的默认262144。
具体可参考DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
解决办法:注入ServerCodecConfigurer,使用ServerCodecConfigurer.getReaders()获取相关配置。
public class RequestBodyRoutePredicateFactory
        extends AbstractRoutePredicateFactory<RequestBodyRoutePredicateFactory.Config> {
    protected static final Log LOGGER = LogFactory.getLog(RequestBodyRoutePredicateFactory.class);
    //注入spring.codec.max-in-memory-size
    @Autowired
    ServerCodecConfigurer codecConfigurer;
    private final List<HttpMessageReader<?>> messageReaders;
    public RequestBodyRoutePredicateFactory() {
        super(RequestBodyRoutePredicateFactory.Config.class);
        this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
    }
    public RequestBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
        super(RequestBodyRoutePredicateFactory.Config.class);
        this.messageReaders = messageReaders;
    }
    public static final String REQUEST_BODY_ATTR = "requestBodyAttr";
    @Override
    public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
        return exchange -> {
            if (!"POST".equals(exchange.getRequest().getMethodValue()) && !"PUT".equals(exchange.getRequest().getMethodValue())) {
                return Mono.just(true);
            }
            Object cachedBody = exchange.getAttribute(REQUEST_BODY_ATTR);
            if (cachedBody != null) {
                try {
                    return Mono.just(true);
                } catch (ClassCastException e) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Predicate test failed because class in predicate does not match the cached body object",
                                e);
                    }
                }
                return Mono.just(true);
            } else {
                return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) ->
//codecConfigurer.getReaders(),来获取spring.codec.max-in-memory-size的配置
ServerRequest.create(exchange.mutate().request(serverHttpRequest).build(),codecConfigurer.getReaders()).bodyToMono(String.class).defaultIfEmpty("").doOnNext((objectValue) -> {
                    if (StringUtils.isBlank(objectValue)) {
                        exchange.getAttributes().put(REQUEST_BODY_ATTR, JSON.toJSONString(exchange.getRequest().getQueryParams()));
                    } else {
                        exchange.getAttributes().put(REQUEST_BODY_ATTR, objectValue);
                    }
                }).map((objectValue) -> true));
            }
        };
    }
.....
}
结果:成功
批量上传文件或者上传大文件时 gateWay报错DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144的更多相关文章
- ThinkPHP 中入口文件中的APP_DEBUG为TRUE时不报错,改为FALSE时报错
		
今天好不容易将一个新闻网做好了(ThinkPHP框架做的),但是,当我将入口文件中定义调试模式设为FALSE,即define('APP_DEBUG',False),然后再刷新网站的时候,就提示报错,报 ...
 - Loadrunner上传文件解决办法(大文件)
		
Loadrunner上传文件解决办法(大文件) 最近再做一个跟海量存储相关的项目测试,需要通过LR模拟用户大量上传和下载文件,请求是Rest或Soap,同时还要模拟多种大小尺寸不一的文件 通常情况下, ...
 - Python组织文件 实践:查找大文件、 用Mb、kb显示文件尺寸 、计算程序运行时间
		
这个小程序很简单原本没有记录下来的必要,但在编写过程中又让我学到了一些新的知识,并且遇到了一些不能解决的问题,然后,然后就很有必要记录一下. 这个程序的关键是获取文件大小,本来用 os.path.ge ...
 - 转:Loadrunner上传文件解决办法(大文件)
		
最近再做一个跟海量存储相关的项目测试,需要通过LR模拟用户大量上传和下载文件,请求是Rest或Soap,同时还要模拟多种大小尺寸不一的文件 通常情况下,都是使用简单的post协议即可: 方法一: we ...
 - GitHub限制上传单个大于100M的大文件
		
工作中遇到这个问题,一些美术资源..unitypackage文件大于100M,Push到GitHub时被拒绝.意思是Push到GitHub的每个文件的大小都要求小于100M. 搜了一下,很多解决办法只 ...
 - Facebook图片存储系统Haystack——存小文件,本质上是将多个小文件合并为一个大文件来降低io次数,meta data里存偏移量
		
转自:http://yanyiwu.com/work/2015/01/04/Haystack.html 一篇14页的论文Facebook-Haystack, 看完之后我的印象里就四句话: 因为[传统文 ...
 - 【laravel5.4】git上clone项目到本地,配置和运行 项目报错:../vendor/aotuload.php不存在
		
1.一般我们直接使用git clone 将git的项目克隆下来,在本地git库和云上git库建立关联关系 2.vendor[扩展]文件夹是不会上传的,那么下载下来直接运行项目,会报错: D:phpSt ...
 - 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射
		
内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...
 - 【基础巩固】文件流读写、大文件移动 FileStream StreamWriter File Path Directory/ ,m资料管理器(递归)
		
C#获取文件名 扩展名 string fullPath = @"d:\test\default.avi"; string filename = Path.GetFileName(f ...
 
随机推荐
- kafka partiton迁移方法与原理
			
在kafka中增加新的节点后,数据是不会自动迁移到新的节点上的,需要我们手动将数据迁移(或者成为打散)到新的节点上 1 迁移方法 kafka为我们提供了用于数据迁移的脚本.我们可以用这些脚本完成数据的 ...
 - Myql 中的事务回滚机制概述 ?
			
事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个 不可分割的工作单位,事务回滚是指将该事务已经完成的对数据库的更新操作撤 销.要同时修改数据库中两个不同表时,如果它们不是一个事务 ...
 - 学习 MongoDB(一)
			
1.介绍 MongoDB是C++语言编写,是一个基于分布式文件存储的开源数据库系统,MongoDB将数据存储为一个文档, 数据结构由键值对(key=>value)组成,MongoDB文档类似于 ...
 - Spring 的 jdbcTemplate 操作
			
1.Spring框架是一站式框架 (1)针对 JavaEE 三层,每一层都有解决技术 (2)在 dao 层,使用 jdbcTemplate 2.Spring对不同的持久化层的技术都进行了封装 (1)j ...
 - 记录md的偏好设置
 - 5. Git初始化及仓库创建和操作
			
4. Git初始化及仓库创建和操作 基本信息设置 1. 设置用户名 git config --global user.name 'itcastphpgit1' 2. 设置用户名邮箱 git confi ...
 - 可想实现一个自己的简单jQuery库?(五)
			
Lesson-4 这个版本我们要增加一个用的非常多的方法! 那就是each! 我们知道each不仅能遍历数组,还能遍历对象. 首先我们需要一个对数组进行验证的方法 function isArray(o ...
 - Mpvue 小程序转 Web 实践总结
			
介绍 Mpvue 是一个使用 Vue.js 开发小程序的前端框架.框架基于 Vue.js 核心,修改了 Vue.js 的 runtime 和 compiler 实现,使其可以运行在小程序环境中,从而为 ...
 - VasSonic Android源码解析
			
VasSonic是腾讯推出的为了提高H5页面首屏加载速度而推出的高性能Hybrid框架,目前广泛应用在QQ商城等Hybrid界面中,以提高用户体验. https://github.com/Tencen ...
 - Springboot集成cache的key生成策略
			
代码接上文:深度理解springboot集成redis缓存之源码解析 ## 1.使用SpEL表达式 @Cacheable(cacheNames = "emp",key = &quo ...