不一样的feign,获取返回code非200的响应

  • Post author:
  • Post category:其他


feign在开发中极大的节省了开发中对接第三方接口的时间,不用在为千奇百怪的三方接口协议去实现不同的请求接口,方便到调用三方接口就像我们自己的接口一样的容易。在大部分情况下不需要特别的处理feign就能很好的为我们工作,然而最进的一个工作让我不得不重新审视feign的使用问题,因为那已经无法完成我的工作了,同时我又不想去手动用httpclien再去写一个请求方法。那是什么问题,我又是怎么解决的呢,下面就简单记录一下。

第一个问题就是在URL中加入了认证信息的,其URL格式这样的http://name:pwd@url.com/a/b,这种如果再用feign去调的话,对方始终是无法调用通过的。默认情况下,feign通过jdk中的HttpURLConnection向下游服务发起http请求,不知道是不是这个原因导致的但这确实不是一个最佳的实践,因此改用功能更强大的httpclient.方法很简单

1.pom文件增加feign-httpclient的依赖(请注意与feign-core的版本保持一致)

<dependency>

<groupId>io.github.openfeign</groupId>

<artifactId>feign-httpclient</artifactId>

<version>9.4.0</version>

</dependency>

2.application.properties配置激活

feign.httpclient.enabled=true

其它配置根据自己需要自行配置,我这里都采用的默认配置

还有一种更麻烦也更常见的问题,feign是只会返回状态码为200时的响应体,而在resultful模式的响应中,某些非200的响应体我们也是需要的,这个时候就需要我们重写errordecode,并将返回内容封装到自定义的异常里面,然后在异常回调时把错误返回出来。

重写errordecode

import com.caiyi.financial.nirvana.pay.common.exception.YofishException;
import feign.Response;
import feign.Util;
import feign.codec.ErrorDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;

import java.io.IOException;

/**
 * @author wxy
 * @create 2019-10-23 17:50
 **/
public class ErrorDecoderConfiguration {
    @Bean
    public ErrorDecoder errorDecoder() {
        return new UserErrorDecoder();
    }
    /**
     * 自定义错误解码器
     */
    public class UserErrorDecoder implements ErrorDecoder {
        private Logger logger = LoggerFactory.getLogger(getClass());
        @Override
        public Exception decode(String methodKey, Response response) {
            // 自定义异常
            YofishException exception = null;
            try {
                // 获取原始的返回内容
                String json = Util.toString(response.body().asReader());
                
                // 业务异常抛出简单的 RuntimeException,保留原来错误信息
                exception = new YofishException(String.valueOf(response.status()),json);
            } catch (IOException ex) {
                logger.error(ex.getMessage(), ex);
            }
            return exception;
        }
    }
}

在需要使用的feign中使用该配置


import com.caiyi.financial.nirvana.pay.common.configuration.KeepErrMsgConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Map;

@FeignClient(name = "RazorpayClient", url = "${razorpay.api.url}", fallbackFactory = RazorpayClientHystric.class, configuration = ErrorDecodeConfiguration.class)
public interface RazorpayApiClient {
    /**
     * 创建联系人
     * @param param
     * @return
     */
    @PostMapping(value = "/contacts", consumes = MediaType.APPLICATION_JSON_VALUE)
    String contracts(@RequestBody Map<String, ?> param);

    /**
     * 创建资金账户
     * @param param
     * @return
     */
    @PostMapping(value = "/fund_accounts", consumes = MediaType.APPLICATION_JSON_VALUE)
    String fundAccounts(@RequestBody Map<String, ?> param);

    /**
     * 支付
     * @param param
     * @return
     */
    @PostMapping(value = "/payouts", consumes = MediaType.APPLICATION_JSON_VALUE)
    String payouts(@RequestBody Map<String, ?> param);

    /**
     * 订单查询
     * @param param
     * @return
     */
    @GetMapping(value = "/payouts/{tradeNo}", consumes = MediaType.APPLICATION_JSON_VALUE)
    String payouts(@PathVariable("tradeNo") String tradeNo);
}

在错误fallback中把错误信息取出

import com.caiyi.financial.nirvana.pay.common.exception.YofishException;
import feign.Response;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author wxy
 * @create 2019-10-15 17:15
 **/
@Slf4j
@Component
public class RazorpayClientHystric implements FallbackFactory<RazorpayApiClient> {

    @Override
    public RazorpayApiClient create(Throwable throwable) {
        return new RazorpayApiClient() {
            @Override
            public String contracts(Map<String, ?> param) {
                log.error("razorpay|创建联系人网络异常,参数:{}", param, throwable);
                if (throwable instanceof YofishException) {
                    return ((YofishException) throwable).getDesc();
                }
                return null;
            }

            @Override
            public String fundAccounts(Map<String, ?> param) {
                log.error("razorpay|创建资金账户网络异常,参数:{}", param, throwable);
                if (throwable instanceof YofishException) {
                    return ((YofishException) throwable).getDesc();
                }
                return null;
            }

            @Override
            public String payouts(Map<String, ?> param) {
                log.error("razorpay|网络异常,参数:{}", param, throwable);
                if (throwable instanceof YofishException) {
                    return ((YofishException) throwable).getDesc();
                }
                return null;
            }

            @Override
            public String payouts(String tradeNo) {
                log.error("razorpay|询网络异常,参数:{}", tradeNo, throwable);
                if (throwable instanceof YofishException) {
                    return ((YofishException) throwable).getDesc();
                }
                return null;
            }
        };
    }
}

这里只简单返回里String,也只提供一个思路,希望能起到抛砖引玉的作用,若果大家有其它思路欢迎评论区见。



版权声明:本文为oXiangYun12345原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。