使用feign调用第三方的http服务,对方返回response,之后这个Decoder接口会将对方的返回值,序列化成我们的返回值,例如下面的代码中,为什么我们能拿到User类型,而不是一个String类型,这就是Decoder来处理的
cpp
@FeignClient(name = "xxx", url = "xxx")
public interface UserAPI {
// 即使对方返回一个符合json格式的String类型,feign也能将这个String转换成User,这就是Decoder接口做的事情
@GetMapping(value = "/xxx/xxx")
User getUser(@RequestParam("userId") Integer userId);
}
下面的代码自定义了一个Decoder,由于Decoder是用来解析对方返回值,所以我这里使用Decoder来打印日志,这样省的每个接口自己打印对方返回值了
步骤1:自定义一个解码器
cpp
package 你的包名
import feign.Response;
import feign.codec.Decoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
/**
* <p>这个类本质上是个第三方Http Response的解码器,本类主要目的是在解码的同时打印日志
*
* @author shiwentian
* @since 1.7.2024
**/
public class OpenFeignPostInterceptor implements Decoder {
private static final Logger log = LoggerFactory.getLogger(OpenFeignPostInterceptor.class);
private final Decoder delegate;
public OpenFeignPostInterceptor(Decoder delegate) {
this.delegate = delegate;
}
@Override
public Object decode(Response response, Type type) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = response.body().asInputStream().read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
byte[] body = byteArrayOutputStream.toByteArray();
String bodyStr = new String(body, StandardCharsets.UTF_8);
log.info("调用第三方接口返回:{}", bodyStr);
return delegate.decode(response.toBuilder().body(bodyStr, StandardCharsets.UTF_8).build(), type);
}
}
步骤2:将上面自定义的解码器通过lite的注入方式,注入到spring容器
cpp
package 你的包名;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 本类用于注册自定义的解码器
*
* @author shiwentian
* @since 1.7.2024
**/
@Configuration
public class DecoderConfig {
// 这个地方需要注意,不能使用@Resource,涉及到泛型问题,如果没有泛型,那么使用@Resource是可以的
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Decoder decode() {
return new OpenFeignPostInterceptor(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))));
}
}
好了,现在启动服务,通过feign调用第三方服务,会发现对方每次返回,都会打印对方的返回值
注意:我没有测试对方服务失败的情况,或者一些其他失败的情况,所以本文中的response.body().asInputStream()
这段代码可能会出现不健壮的情况,需要你自己对失败的情况进行处理
源代码参考:Spring Cloud Open Feign 2.2.9版本org.springframework.cloud.openfeign.FeignClientsConfiguration
类的public Decoder feignDecoder()
方法