使用feign拦截响应,打印日志
使用feign拦截响应,打印日志
1、前言
spring cloud 对feign调用对返回值做了包装处理,通过一些列Decoder来处理feign访问的返回值。
具体流程 从SynchronousMethodHandler中的decoder开始会经历如下几个decoder:
OptionalDecoder -> ResponseEntityDecoder -> SpringDecoder
可以在 FeignClientsConfiguration 看到有对上面三个decoder的定义,有兴趣的可以自行阅读源码。
feign返回值拦截 + response只能读取一次处理
feign返回值拦截只需要自定义一个coder,替换 FeignClientsConfiguration 中的 decoder定义即可,具体代码如下:
配置自定义decoder:
/**
* feign返回值拦截
* @author liufei
*/
public final class ResultStatusDecoder implements Decoder {
public static final String CONTENT_KEY = "content";
final Decoder delegate;
public ResultStatusDecoder(Decoder delegate) {
Objects.requireNonNull(delegate, "Decoder must not be null. ");
this.delegate = delegate;
}
@Override
public Object decode(Response response, Type type) throws IOException {
// 判断是否返回参数是否是异常
String resultStr = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);
// 拿到返回值,进行自定义逻辑处理
log.info("do business ,result msg ->{}",resultStr);
// 回写body,因为response的流数据只能读一次,这里回写后重新生成response
return delegate.decode(response.toBuilder().body(resultStr, StandardCharsets.UTF_8).build(), type);
}
}
由于response中的body只能读取一次,所以最后需要把body回写,再重新生成response传递到下一个decoder
配置自定义bean:
@Configuration
public class SupportAutoConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Decoder feignDecoder() {
return new ResultStatusDecoder(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))));
}
}