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

本文探讨Feign在处理特定场景下的局限性及解决方案,包括URL认证信息处理与非200状态码响应解析,通过引入feign-httpclient依赖及自定义错误解码器,提升Feign在复杂场景下的灵活性。

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,也只提供一个思路,希望能起到抛砖引玉的作用,若果大家有其它思路欢迎评论区见。

Feign 是一种声明式的 Web 服务客户端,它简化了 HTTP 请求的构建与处理。在某些场景下,开发者可能希望禁用 Feign返回结果的一致性检查,以适应特定的业务需求或绕过某些校验逻辑。 可以通过自定义解码器(Decoder)来实现对 Feign 返回值的处理逻辑进行调整。Feign 默认使用 `ResponseEntityDecoder` 来解析响应内容,并对其结构进行验证。如果需要禁用一致性检查,可以替换默认的解码器为一个自定义实现,该实现执行任何额外的校验操作。 以下是一个示例配置类,展示了如何通过替换 Feign 的解码器来禁用返回结果一致性检查: ```java import feign.Decoder; import feign.Response; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; import java.lang.reflect.Type; @Configuration public class FeignClientConfig { @Bean public Decoder feignDecoder() { return new Decoder() { @Override public Object decode(Response response, Type type) throws IOException { // 可根据实际需要实现具体的解码逻辑,这里直接跳过一致性检查 return null; } }; } } ``` 上述代码中定义了一个新的 `Decoder` 实现,其 `decode` 方法没有执行任何具体的数据转换逻辑,而是直接返回了 `null`。当然,在实际应用中应该根据接口的实际返回类型和格式(如 JSON、XML 等)实现相应的解析过程,同时避免对响应数据进行结构化校验[^1]。 此外,还可以结合日志记录功能进一步调试 Feign 客户端的行为。例如,通过启用 Feign 的详细日志输出模式,可以在运行时查看完整的请求与响应信息,从而帮助确认返回结果是否符合预期: ```java import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignLoggerConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } } ``` 通过将 `feign.Logger.Level` 设置为 `FULL`,可以开启最详细的日志记录级别,包括请求头、请求体、响应头和响应体等内容的输出[^2]。这有助于分析 Feign 在处理响应时的具体行为,尤其是在尝试禁用某些内置检查机制的情况下。 最后,确保 Feign 客户端使用的配置类被正确加载并生效。通常可以通过在 Feign 接口上添加 `@FeignClient` 注解并指定 `configuration` 属性来关联配置类: ```java import com.example.client.UserFeignClientFallback; import com.example.model.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(name = "user-service", fallback = UserFeignClientFallback.class, configuration = FeignClientConfig.class) public interface UserFeignClient { @GetMapping(value = "/{id}") User findById(@PathVariable("id") Long id); } ``` 在以上示例中,`FeignClientConfig` 类中的配置会被应用于 `UserFeignClient` 接口的所有远程调用过程中,从而实现对返回结果一致性检查的控制[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值