这里是weihubeats,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党
最近在配置研究网关的超时时间,有这么一个需求。
服务路由转发接口的超时时间总体是5s,但是部分特殊服务可能需要配置更长的超时时间,比如10s。
要实现这个需求怎么处理呢?其实很简单,大致如下配置
spring:
cloud:
gateway:
httpclient:
response-timeout: 3s
pool:
type: fixed
max-connections: 200
max-idle-time: 5000
acquire-timeout: 10000
routes:
- id: order-service
predicates:
- Path=/xiaozou/order-service/**
filters:
- StripPrefix=2
uri: lb://order-service
- id: pay-service
predicates:
- Path=/xiaozou/pay-service/**
filters:
- StripPrefix=1
uri: http://localhost:9999/pay-service
metadata:
response-timeout: 5000
这里我们配置了两个服务路由order-service
、pay-service
配置了全局的请求超时时间
spring.cloud.gateway.httpclient.response-timeout=3s
然后配置了单个服务的超时时间5000
(5s)
正常看这个配置和操作是没问题
我们的配置中心使用的是apollo
,所以配置都放在apollo
中
然后我们通过debug查看源码NettyRoutingFilter
发现一个bug
在yaml配置的Integer类型变成string了
导致判断
if (responseTimeoutAttr != null && responseTimeoutAttr instanceof Number)
中的responseTimeoutAttr instanceof Number
失效,从而导致metadata
中配置的response-timeout
失效
这个是由于apollo
底层实现使用了Properties
作为配置存储,所以虽然在apollo解析yaml时能知道配置的类型(如Integer),但是在存储的时候都会统一转为String类型,如下图所示
所以apollo
在使用会有这个bug:@ConfigurationProperties注解导致类型从Integer转为String:https://github.com/apolloconfig/apollo/issues/2896
感兴趣的可以查看这个issues
,对此apollo
并没有打算修复这个问题
最简单的方式就是我们修改源码,这里就不用重新编译spring cloud gateway
源码了
我们直接在项目中新建一个org.springframework.cloud.gateway.filter
包
然后新建类NettyRoutingFilter
然后修改getResponseTimeout
这个方法为如下
private Duration getResponseTimeout(Route route) {
Object responseTimeoutAttr = route.getMetadata().get(RESPONSE_TIMEOUT_ATTR);
try {
if (responseTimeoutAttr != null) {
long routeResponseTimeout = Long.parseLong((String) responseTimeoutAttr);
if (routeResponseTimeout >= 0) {
return Duration.ofMillis(routeResponseTimeout);
}
else {
return null;
}
}
} catch (Exception e) {
log.error("get responseTimeoutAttr error, so use default responseTimeout, error ", e);
}
return properties.getResponseTimeout();
}
核心是删除responseTimeoutAttr instanceof Number
判断,添加类型转换
这样就解决了
我们在使用Apollo
配置文件的时候一定要注意这个坑,就是@ConfigurationProperties注解导致类型从Integer转为String