Feign调用接口解决处理内部异常的问题

网友投稿 398 2023-01-03

Feign调用接口解决处理内部异常的问题

问题描述:

当使用feign调用接口,出现400~500~的接口问题时。会出错feign:FeignException。(因为是错误,只能用catch Throwable,不可使用catch Exception捕获异常)导致程序无法继续运行。

问题原因:

由于feign默认的错误处理类是FunFeignFallback会throw new AfsBaseExceptio导致外部无法捕获异常。

package com.ruicar.afs.cloud.common.core.feign;

import com.alibaba.fastjson.JSONObject;

import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;

import com.ruicar.afs.cloud.common.core.util.IResponse;

import feign.FeignException;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.extern.slf4j.Slf4j;

import org.springframework.cglib.proxy.MethodInterceptor;

import org.springframework.cglib.proxy.MethodProxy;

import org.springframework.lang.Nullable;

import java.lang.refleearjptlct.Method;

import java.util.Objects;

@Data

@AllArgsConstructor

@Slf4j

public class FunFeignFallback implements MethodInterceptor {

private final Class targetType;

private final String targetName;

private final Throwable cause;

private static byte JSON_START = '{';

@Nullable

@Override

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

String errorMessage = cause.getMessage();

if (!(cause instanceof FeignException)) {

log.error("FunFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);

log.error("feign调用失败", cause);

return IResponse.fail("请求失败,请稍后再试");

}

int status = ((FeignException.FeignClientException) this.cause).status();

boolean isAuthFail = (status==426||status==403||status==401)&&"afs-auth".equals(targetName);

FeignException exception = (FeignException) cause;

if(isAuthFail){

log.warn("授权失败==========原始返回信息:[{}]",exception.contentUTF8());

}else {

log.error("FunFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);

log.error("", cause);

log.error("原始返回信息{}",exception.contentUTF8());

}

if(method.getReturnType().equals(Void.class)){

throw new AfsBaseException("接口调用失败");

}

if(method.getReturnType().equals(IResponse.class)){

if(exception instanceof FeignException.Forbidden){

return IResponse.fail("没有权限").setCode("403");

}

if(exception instanceof FeignException.NotFound){

return IResponse.fail("请求路径不存在").setCode("404");

http://}

if(exception instanceof FeignException.BadRequest){

return IResponse.fail("参数错误").setCode("400");

}

if(exception.content()==null||exception.content().length==0){

return IResponse.fail("请求失败,请稍后再试");

}

if(JSON_START==exception.content()[0]){

return JSONhttp://Object.parseObject(exception.content(),IResponse.class);

}else{

return IResponse.fail(exception.contentUTF8());

}

}else{

try {

if(method.getReturnType().equals(String.class)){

return exception.contentUTF8();

}else if(method.getReturnType().equals(JSONObject.class)){

if(JSON_START==exception.content()[0]){

return JSONObject.parseObject(exception.content(), JSONObject.class);

}

}else if(!method.getReturnType().equals(Object.class)){

return JSONObject.parseObject(exception.content(), method.getReturnType());

}

if(JSON_START==exception.content()[0]){

JSONObject jsonObject = JSONObject.parseObject(exception.content(), JSONObject.class);

if(jsonObject.containsKey("code")&&jsonObject.containsKey("msg")) {

return jsonObject.toJavaObject(IResponse.class);

}

}

}catch (Throwable e){}

throw new AfsBaseException("接口调用失败");

}

}

@Override

public boolean equals(Object o) {

if (this == o) {

return true;

}

if (o == null || getClass() != o.getClass()) {

return false;

}

FunFeignFallback> that = (FunFeignFallback>) o;

return targetType.equals(that.targetType);

}

@Override

public int hashCode() {

return Objects.hash(targetType);

}

}

问题解决:自定义feignFallback异常处理:

1.自定义异常处理 InvoiceApiFeignFallbackFactory

package com.ruicar.afs.cloud.invoice.factory;

import com.ruicar.afs.cloud.invoice.fallback.InvoiceApiFeignFallback;

import com.ruicar.afs.cloud.invoice.feign.InvoiceApiFeign;

import feign.hystrix.FallbackFactory;

import org.springframework.stereotype.Component;

@Component

public class InvoiceApiFeignFallbackFactory implements FallbackFactory {

@Override

public InvoiceApiFeign create(Throwable throwable) {

InvoiceApiFeignFallback invoiceApiFeignFallback = new InvoiceApiFeignFallback();

invoiceApiFeignFallback.setCause(throwable);

return invoiceApiFeignFallback;

}

}

2.feign调用 InvoiceApiFeignFallbackFactory

package com.ruicar.afs.cloud.invoice.feign;

import com.alibaba.fastjson.JSONObject;

import com.ruicar.afs.cloud.common.core.feign.annotations.AfsFeignClear;

import com.ruicar.afs.cloud.invoice.dto.InvoiceCheckDto;

import com.ruicar.afs.cloud.invoice.factory.InvoiceApiFeignFallbackFactory;

import io.swagger.annotations.ApiOperation;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestHeader;

import java.util.Map;

/**

* @description: 发票验证接口

* @author: rongji.zhang

* @date: 2020/8/14 10:32

*/

@FeignClient(name = "invoice", url = "${com.greatwall.systems.invoice-system.url}" ,fallbackFactory = InvoiceApiFeignFallbackFactory.class)

public interface InvoiceApiFeign {

/**

*

* @param dto

* @return

*/

@ApiOperation("获取业务数据API接口")

@PostMapping(value = "/vi/check")

@AfsFeignClear(true)//通过此注解防止添加内部token

JSONObject InvoiceCheck(@RequestBody InvoiceCheckDto dto, @RequestHeader Map headers);

}

3.实现自定义报错处理

package com.ruicar.afs.cloud.invoice.fallback;

import com.alibaba.fastjson.JSONObject;

import com.ruicar.afs.cloud.invoice.dto.InvoiceCheckDto;

import com.ruicar.afs.cloud.invoice.feign.InvoiceApiFeign;

import lombok.Setter;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Component;

import java.util.Map;

/**

* @author Fzero

* @date 2019-01-24

*/

@Slf4j

@Component

public class InvoiceApiFeignFallback implements InvoiceApiFeign {

@Setter

private Throwable cause;

/**

* @param dto

* @param headers

* @return

*/

@Override

public JSONObject InvoiceCheck(InvoiceCheckDto dto, Map headers) {

log.error("feign 接口调用失败", cause);

return null;

}

}

Feign远程调用失败-----丢请求头

@FeignClient("guli-cart")

public interface CartFenignService {

@GetMapping("/currentUserCartItems")

List getCurrentUserCartItems();

}// 这样去掉接口时其实Feign在底层是一个全新的requst所有请求头就没有了

解决办法使用Feign远程掉用拦截器,在远程请求是先创建拦截器

@Bean("requestInterceptor")

public RequestInterceptor requestInterceptor() {

return new RequestInterceptor() {

@Override

public void apply(RequestTemplate template) {

/**

* 把以前的Cookie放到新请求中去 原理就是运用了同一线程数据共享 ThreadLocal

*/

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

String cookie = request.getHeader("Cookie");

template.header("Cookie", cookie);

}

};

}

但是上面的办法只能解决同意线程问题,在多线程下还是会丢失请求头

多线程下解决办法:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

把请求单独拿出来给每个线程单独

RequestContextHolder.setRequestAttributes(requestAttributes);

这样就可以了~

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何查询网站api接口(如何查询网站api接口类型)
下一篇:Java使用poi导出ppt文件的实现代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~