最近在做一个下载功能时,发现直接调用服务是可以下载的,但是通过gateway路由下载会报NPE异常,具体如下

java.lang.NullPointerException: null
at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011) ~[na:1.8.0_111]
at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006) ~[na:1.8.0_111]
at org.springframework.cloud.gateway.filter.NettyRoutingFilter.lambda$filter$3(NettyRoutingFilter.java:117) ~[spring-cloud-gateway-core-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:177) ~[reactor-core-3.1.8.RELEASE.jar!/:3.1.8.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108) ~[reactor-core-3.1.8.RELEASE.jar!/:3.1.8.RELEASE]
at reactor.core.publisher.FluxRetryPredicate$RetryPredicateSubscriber.onNext(FluxRetryPredicate.java:81) ~[reactor-core-3.1.8.RELEASE.jar!/:3.1.8.RELEASE]
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:146) ~[reactor-core-3.1.8.RELEASE.jar!/:3.1.8.RELEASE]
at reactor.ipc.netty.channel.PooledClientContextHandler.fireContextActive(PooledClientContextHandler.java:85) ~[reactor-netty-0.7.8.RELEASE.jar!/:0.7.8.RELEASE]
at reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:578) ~[reactor-netty-0.7.8.RELEASE.jar!/:0.7.8.RELEASE]
at reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:136) ~[reactor-netty-0.7.8.RELEASE.jar!/:0.7.8.RELEASE]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) ~[netty-codec-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) ~[netty-codec-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) ~[netty-transport-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:808) ~[netty-transport-native-epoll-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:408) ~[netty-transport-native-epoll-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:308) ~[netty-transport-native-epoll-4.1.25.Final.jar!/:4.1.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) ~[netty-common-4.1.25.Final.jar!/:4.1.25.Final]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_111]

分析异常 发现其中和spring gateway有关的是这句

 at org.springframework.cloud.gateway.filter.NettyRoutingFilter.lambda$filter$3(NettyRoutingFilter.java:117) ~[spring-cloud-gateway-core-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]

定位到相关的代码片段查看 org.springframework.cloud.gateway.filter.NettyRoutingFilter

return this.httpClient.request(method, url, req -> {
final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)
.headers(httpHeaders)
.chunkedTransfer(chunkedTransfer)
.failOnServerError(false)
.failOnClientError(false); if (preserveHost) {
String host = request.getHeaders().getFirst(HttpHeaders.HOST);
proxyRequest.header(HttpHeaders.HOST, host);
} return proxyRequest.sendHeaders() //I shouldn't need this
.send(request.getBody().map(dataBuffer ->
((NettyDataBuffer)dataBuffer).getNativeBuffer()));
}).doOnNext(res -> {
ServerHttpResponse response = exchange.getResponse();
// put headers and status so filters can modify the response
HttpHeaders headers = new HttpHeaders(); res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue())); exchange.getAttributes().put("original_response_content_type", headers.getContentType()); HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE); response.getHeaders().putAll(filteredResponseHeaders);
HttpStatus status = HttpStatus.resolve(res.status().code());
if (status != null) {
response.setStatusCode(status);
} else if (response instanceof AbstractServerHttpResponse) {
// https://jira.spring.io/browse/SPR-16748
((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());
} else {
throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());
} // Defer committing the response until all route filters have run
// Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
}).then(chain.filter(exchange));

出问题的为这句

exchange.getAttributes().put("original_response_content_type", headers.getContentType());

因为ConcurrentHashMap不允许出现null值,可见此时header中的ContentType为空导致。像下载文件,或者在controller中进行跳转时,都会出现这种情况。

这个bug在spring cloud gateway的github上作者已经说明的解决方案:将springcloud gateway升级至2.0.1或以上的版本即可,我之前使用的是2.0.0,对应

springcloud的版本 为 Finchley.RELEASE

我升级到了2.0.2 对应springcloud的版本为 Finchley.SR2   对应部分的代码

    return responseMono.doOnNext(res -> {
ServerHttpResponse response = exchange.getResponse();
// put headers and status so filters can modify the response
HttpHeaders headers = new HttpHeaders(); res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue())); String contentTypeValue = headers.getFirst(HttpHeaders.CONTENT_TYPE);
if (StringUtils.hasLength(contentTypeValue)) {
exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, contentTypeValue);
} HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE); response.getHeaders().putAll(filteredResponseHeaders);
HttpStatus status = HttpStatus.resolve(res.status().code());
if (status != null) {
response.setStatusCode(status);
} else if (response instanceof AbstractServerHttpResponse) {
// https://jira.spring.io/browse/SPR-16748
((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());
} else {
throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());
} // Defer committing the response until all route filters have run
// Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
})
.onErrorMap(t -> properties.getResponseTimeout() != null && t instanceof ReadTimeoutException,
t -> new TimeoutException("Response took longer than timeout: " +
properties.getResponseTimeout()))
.then(chain.filter(exchange));

可以看到关键部分的代码 和之前的相比较 已经做了判空

      String contentTypeValue = headers.getFirst(HttpHeaders.CONTENT_TYPE);
if (StringUtils.hasLength(contentTypeValue)) {
exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, contentTypeValue);
}

springcloud gateway nullpointerexception (NettyRoutingFilter)的更多相关文章

  1. SpringCloud Gateway 测试问题解决

    本文针对于测试环境SpringCloud Gateway问题解决. 1.背景介绍 本文遇到的问题都是在测试环境真正遇到的问题,不一定试用于所有人,仅做一次记录,便于遇到同样问题的干掉这些问题. 使用版 ...

  2. 基于springcloud gateway + nacos实现灰度发布(reactive版)

    什么是灰度发布? 灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式.在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B ...

  3. SpringCloud gateway自定义请求的 httpClient

    本文为博主原创,转载请注明出处: 引用 的 spring cloud gateway 的版本为 2.2.5 : SpringCloud gateway 在实现服务路由并请求的具体过程是在 org.sp ...

  4. SpringCloud Gateway入门

    本文是介绍一下SpringCloud Gateway简单路由转发使用. SpringCloud Gateway简介 SpringCloud是基于Spring Framework 5,Project R ...

  5. 使用springcloud gateway搭建网关(分流,限流,熔断)

    Spring Cloud Gateway Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 ...

  6. SpringCloud Gateway(八)

    搭建SpringCloud Gateway 创建microservicecloud-springcloud-gateway-9528工程 pom文件 依赖: <dependencies> ...

  7. 体验SpringCloud Gateway

    Spring Cloud Gateway是Spring Cloud技术栈中的网关服务,本文实战构建一个SpringCloud环境,并开发一个SpringCloud Gateway应用,快速体验网关服务 ...

  8. spring-cloud-kubernetes与SpringCloud Gateway

    本文是<spring-cloud-kubernetes实战系列>的第五篇,主要内容是在kubernetes上部署一个SpringCloud Gateway应用,该应用使用了spring-c ...

  9. SpringCloud gateway (史上最全)

    疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -25[ 博客园 总入口 ] 前言 ### 前言 疯狂创客圈(笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家 ...

随机推荐

  1. python关于操作文件的相关模块(os,sys,shutil,subprocess,configparser)

    一:os模块 os模块提供了许多允许你程序与操作系统直接交互的功能 功能 说明 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirna ...

  2. 基于bs4库的HTML内容查找方法

    一.信息提取实例 提取HTML中所有的URL链接 思路:1)搜索到所有的<a>标签 2)解析<a>标签格式,提取href后的链接内容 >>> import r ...

  3. scp--linux命令

    不同服务器之间传输文件, 第一种方式: scp TC_20171230_RCE_15_37_34_build-20.tar.gz test@192.168.18.90://data/build/ 缺点 ...

  4. Spring Boot Json 之 Jackjson Fastjson

    Json 是目前互联网应用使用最为广泛的信息交换格式之一.Spring Boot 内置了 Jackson .Json 在应用中主要体现在以下功能: 序列化 反序列化 字段格式化 验证自动化 目前长用的 ...

  5. java中路径的问题

    在java中,涉及路径的问题有很多,不管在windows还是linux系统中,不要纠结”/“分隔符的使用,在windows系统中,资源加载器会自动的将”/“转换成”\“. 在java中获取资源的方式有 ...

  6. 卫哲VS投行女,秋后算账是阿里的企业文化吗?

    编辑 | 于斌 出品 | 于见(mpyujian) 提到马云,大家都会想到淘宝,阿里,也都期待阿里巴巴的马云爸爸能够给我们免单,从而省去我们每天为钱烦恼的后顾之忧.虽然今天要吃的瓜是有关阿里的,但是并 ...

  7. Burpsuite 工具详解(常用模块之proxy、spider 、decoder)

    Burpsuite常用模块之proxy.spider .decoder                                                 是一款集成化渗透测试工具(jav ...

  8. windows下如何快速删除大文件

    rmdir  磁盘:\文件夹的名字  /s /q; eg:rmdir E:\vue_workspace\KB\day08    /s/q /S 表示除目录本身外,还将删除指定目录下的所有子目录和文件. ...

  9. 精简DOCKER环境

    docker system prune -a WARNING! This will remove:  - all stopped containers  - all networks not used ...

  10. dp求解各种子串子序列

    目录 概念 最长上升子序列 最长连续子串 最长公共子序列 最长公共上升子序列 注:dp可能并不是求解该这些问题的最优算法,这里只是做一个dp 算法的简介. 概念 定义:假设现有一个 string = ...