OpenFeign返回结果content-type类型解析扩展

     之前有一篇文章(OpenFeign 自定义结果转换)介绍了怎么自定义解析OpenFein的返回结果。之后再使用中发现,在接口正常的情况下。都能按照我们自定义的情况展示。

       但是在现实应用中我们可能要经过很多次代理。每个代理的错误返回都可能存在不一样的情况。这就会导致之前的转换出问题。而且很多时候我们只需要部分接口做转换,而不是所有的接口做转换,也有可能是需要处理某一种 OpenFein没有实现的 contentType的转换方式。

        基于以上问题,所以我想,如果能在原有的OpenFein的解析方式中增加自定义的解析方式。例如假如  我的content-type=json/1231231 是 就用自定义的解析方式。至于其他的已有类型就用OpenFein默认的转换解析方式。

        通过查看资料和研究OpenFein的解析源码。我们可以知道,OpenFeign的结果解析转换是依赖于Decoder类的decode()方法。

        在FeignClientsConfiguration可以找到OpenFeign的解析注入方式:

@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	//..... 忽略代码

    /**
     *
     *这是注入解析接口返回的转换的方法
     */
	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
		return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers)));
	}

    /**
     *
     *这是注入解析接口请求的转换的方法
     */
	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
	public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider,
			ObjectProvider<HttpMessageConverterCustomizer> customizers) {
		return springEncoder(formWriterProvider, encoderProperties, customizers);
	}
    //...忽略代码
}

查看OptionalDecoder源码可以知道:

import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.Optional;

public final class OptionalDecoder implements Decoder {
  final Decoder delegate;

  public OptionalDecoder(Decoder delegate) {
    Objects.requireNonNull(delegate, "Decoder must not be null. ");
    this.delegate = delegate;
  }

  @Override
  public Object decode(Response response, Type type) throws IOException {
    if (!isOptional(type)) {
        //这里调用了默认的解析方式
      return delegate.decode(response, type);
    }
    if (response.status() == 404 || response.status() == 204) {
      return Optional.empty();
    }
    Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
    return Optional.ofNullable(delegate.decode(response, enclosedType));
  }

  static boolean isOptional(Type type) {
    if (!(type instanceof ParameterizedType)) {
      return false;
    }
    ParameterizedType parameterizedType = (ParameterizedType) type;
    return parameterizedType.getRawType().equals(Optional.class);
  }
}

参照 OptionalDecoder 我们可以实现自己的 结果解析器。在Content-Type为指定类型时,使用我们自己的解析器,其他则继续调用默认的解析转换:

public class FeignResultDecoder implements Decoder {

    private static final Logger LOGGER = LoggerFactory.getLogger(FeignResultDecoder.class);

    final Decoder delegate;

    public FeignResultDecoder(Decoder delegate) {
        Objects.requireNonNull(delegate, "Decoder must not be null. ");
        this.delegate = delegate;

    }

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        if (response.body() != null && response.headers().get("Content-Type").contains("json/text;charset=UTF-8")) {
            String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
            if (StringUtils.isNotEmpty(bodyStr)) {
                //对结果进行转换
                try {
                    JavaType javaType = TypeFactory.defaultInstance().constructType(type);
                    return new ObjectMapper().readValue(bodyStr, javaType);
                } catch (IOException e) {
                    LOGGER.error("将JSON转换为对象时发生错误,url :{}, 数据:{}", response.request().url(), bodyStr);
                    throw new IllegalArgumentException("将JSON转换为对象时发生错误" , e);
                }
            } else {
                LOGGER.error("feign结果返回为空, url:{}, status:{}", response.request().url(), response.status());
            }
        }
        //这里和可以加入其他的自定义类型扩展实现
        else {
            return delegate.decode(response, type);
        }
        return null;
    }
}

config配置: 对所有配置生效

@Configuration
public class ExternalMvcConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
        return new FeignResultDecoder(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers))));
    }
}

通过以上的方式就可以在原有的解析方法上加入自定义的解析方式了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值