使用feign调用第三方的http服务,对方返回response,之后这个Decoder接口会将对方的返回值,序列化成我们的返回值,例如下面的代码中,为什么我们能拿到User类型,而不是一个String类型,这就是Decoder来处理的
@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:自定义一个解码器
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;}@Overridepublic 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容器
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是可以的@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Beanpublic 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()
方法