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

相关推荐
222you1 天前
Ubuntu当中的Docker安装和镜像管理
ubuntu·spring cloud·docker
YDS8291 天前
SpringCloud —— Elasticsearch的DSL查询
java·elasticsearch·搜索引擎·spring cloud
梵得儿SHI1 天前
Spring Cloud 高并发订单服务实战:从创建流程优化到 Seata 分布式事务落地(附代码 + 架构图)
分布式·spring·spring cloud·高并发·异步削峰·完整解决方案·限流降级
YDS8292 天前
SpringCloud —— Elasticsearch入门详解
spring·elasticsearch·spring cloud
小七mod2 天前
【Nacos】Nacos1.4.x服务注册源码分析
java·spring cloud·微服务·nacos·源码·集群·注册中心
sanggou2 天前
Spring Cloud负载均衡组件到底是哪一个?
spring·spring cloud·负载均衡
重庆小透明2 天前
微服务,不仅仅是“小服务”
java·后端·spring cloud·微服务·云原生·架构
liurunlin8882 天前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
ab1515172 天前
3.11二刷基础78、79,完成进阶
spring cloud