一、问题背景
需要调用第三方和风天气的api,获取天气信息
编写了如下使用openfeign调用的接口
二、问题描述
3、使用上述的feign调用第三方api,产生2个问题,问题1:401(==偶现==)、问题2:乱码(==必现==),而通过断点排查,调用api的header和参数都是正确的
feign.FeignException$Unauthorized: [401] during [GET] to [] [IWeatherApiService#getWeatherNow(String,String)]: [��U̱� �_!�ZA\'6W ���r�84�鿋n�ox3 31��8��n��@��B�5&�S?^�$\"kOw��X��G�;֞�UͮJ$NoТ$�w��s@qih�o�Y�w�(�[S��}��֫��j��cV��HE4,���N��] at feign.FeignException.clientErrorStatus(FeignException.java:197)
三、问题原因
3.1、问题1:乱码
1、这个第三方api的响应开启了gzip压缩,响应体是 gzip 压缩的
2、Feign 默认使用 JDK 自带的 HttpURLConnection 作为 HTTP Client,不支持处理gizp
3.2、问题2:401
1、和风天气支持header中放入Authorization的认证方式
2、我们服务依赖的feign的基础服务中,实现了RequestInterceptor,重写了其apply方法,将我们的一些信息放入了header,其中,有些场景会有Authorization放入,而这个拦截器是在我们放入之后,因此会将我们的认证信息覆盖掉
因此就出现了401
四、问题解决
4.1、乱码问题解决
feign:
okhttp:
enabled: true
max-connections: 200
max-connections-per-route: 50
4.2、401问题解决
4.2.1、方式1:覆盖feign的基础服务中的拦截器
- 编写拦截器,认证信息放入header
public class WeatherFeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(\"Authorization\", \"1111\");
}
}
- 编写配置文件
@Configuration
public class WeatherFeignConfig {
// 注意这里方法名需要跟依赖的项目的拦截器的配置文件中的一样,这样是起到覆盖作用的重要环节
@Bean
public RequestInterceptor requestInterceptor() {
return new WeatherFeignRequestInterceptor();
}
}
这样的话,就会覆盖feign的基础服务中的拦截器,仅使用我们写的这个拦截器,就不会出现Authorization被覆盖的问题了,也就不会出现401了
4.2.2、方式2:调整拦截器执行顺序,把我们的拦截器放在最后面
- 修改feign的基础服务中的拦截器
public class BaseFeignRequestInterceptor implements RequestInterceptor, Ordered {
public void apply(RequestTemplate requestTemplate) {
}
public int getOrder() {
return 2147483547;
}
}
- 当前服务的拦截器增加排序
@Slf4j
public class WeatherApiFeignRequestInterceptor implements RequestInterceptor, Ordered {
private static final String WEATHER_API_SERVICE = \"weatherApiService\";
@Override
public void apply(RequestTemplate template) {
// 非天气服务接口,不处理
if (!WEATHER_API_SERVICE.equalsIgnoreCase(template.feignTarget().name())) {
return;
}
// 清空所有现有的请求头
template.headers(null);
// 只添加你需要的请求头
template.header(\"Authorization\", 11111);
template.header(\"Content-Type\", \"application/json\");
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 99;
}
}
- 编写配置文件
@Configuration
public class WeatherFeignConfig {
// 这里方法名随便写
@Bean
public RequestInterceptor weatherRequestInterceptor() {
return new WeatherFeignRequestInterceptor();
}
}
如此,这个两个拦截器都会生效,不过我们自定义的拦截器会更晚执行,就不会出现我们的认证信息被覆盖的问题了



还没有评论呢,快来抢沙发~