小程序容器助力企业在金融与物联网领域实现高效合规运营,带来的新机遇与挑战如何管理?
1566
2023-01-05
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
private final Class
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
}
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
log.error("feign 接口调用失败", cause);
return null;
}
}
Feign远程调用失败-----丢请求头
@FeignClient("guli-cart")
public interface CartFenignService {
@GetMapping("/currentUserCartItems")
List
}// 这样去掉接口时其实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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~