Spring-cloud-openfeign解码器Decoder接口(后置拦截器)

使用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() 方法

相关推荐
维李设论10 小时前
Node.js的Web服务在Nacos中的实践
前端·spring cloud·微服务·eureka·nacos·node.js·express
Doker 多克17 小时前
IntelliJ IDEA Docker集成
spring cloud·docker·intellij-idea
Hello Dam18 小时前
面向微服务的Spring Cloud Gateway的集成解决方案:用户登录认证与访问控制
spring cloud·微服务·云原生·架构·gateway·登录验证·单点登录
小马爱打代码1 天前
SpringCloud(注册中心+OpenFeign+网关+配置中心+服务保护+分布式事务)
分布式·spring·spring cloud
小笨猪-1 天前
统⼀服务⼊⼝-Gateway
java·spring cloud·微服务·gateway
岁月变迁呀1 天前
Spring Cloud Gateway 源码
java·spring·spring cloud·gateway
岁月变迁呀1 天前
Eureka服务注册源码
spring cloud·eureka
橘子在努力2 天前
【橘子微服务】spring cloud function的编程模型
spring cloud·微服务·架构
杨荧2 天前
【开源免费】基于Vue和SpringBoot的靓车汽车销售网站(附论文)
java·前端·javascript·vue.js·spring boot·spring cloud·开源