在feign.hystrix.enable=false情况下,微服务提供方跑出自定义异常,微服务调用方怎么捕获这个自定义异常?
分两种情况:
1.如果微服务提供了接口声明,微服务调用工程引用了这个接口声明jar,有异常可以正常捕获。
2.如果微服务提供方以RestController的方式对外提供服务(例如/api/login),则在微服务调用工程中要自定义错误解码处理。
3.还有一种说法是利用@HystrixCommand,人家的原话是:
Thanks. However, I think disabling Feign hystrix support (feign.hystrix.enabled=false) and using a @HystrixCommand on the caller method is simpler. That's what I'm doing now. – Abhijit Sarkar Nov 30 '16 at 8:56
And you use ignroeExceptions of @HystrixCommand? – Roi Ezra Dec 1 '16 at 11:50
Yes, using ignoreExceptions. – Abhijit Sarkar Dec 5 '16 at 3:37
方法2使用举例:
微服务提供方:
@RestController
@RequestMapping("api")
public class UserController{
@Autowired
private UserFacadeService userFacadeService;
@RequestMapping(vlaue="/login", method=RequestMethod.POST)
public Token login(@RequestBody UserDto user) throws MyException{
return userFacadeService.getLoginToken(user);
}
}
微服务调用方:
1.FeignClient中定义configuration采用自定义配置
@FeignClient(name="serviceProvide", fallback=UserServiceImpl.class, configuration={KeepErrMsgConfiguration.class})
public interface UserService{
@RequestMapping(value="/api/login", method=RequestMethod.POST)
public Token login(@RequestBody UserDto user) throws MyException;
}
@Service
public UserServiceImpl implements UserService{
private final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Override
public Token login(@RequestBody UserDto user) throws MyException{
log.error("调用{}异常:{}","serviceProvide:/api/login",user);
return null;
}
}
2.自定义错误解码
import com.alibaba.fastjson.JSON;
import com.test.common.exception.MyException;
import feign.Response;
import feign.Util;
import feign.codec.ErrorDecoder;
import org.apach.commons.langs3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Map;
class MyErrDecoder implements ErrorDecoder{
private final Logger log = LoggerFactory.getLogger(MyErrDecoder.class);
private static final String ERR_CODE="500";
private static final String SPLIT=":";
@Override
public Exception decode(String methodKey, Response response){
Exception excepiton = null;
try{
//获取原始的返回内容
String json = Utils.toString(response.body().asReader());
//将返回的内容反序列化位Result,这里应根据自身项目做修改
Map<String, Object> result = JSON.parseObject(json, Map.class);
log.error("", result);
String msg = result.get("msg");
String code = String.valueOf(result.get("code"));
exception = new RuntimeException(json);
if(ERR_CODE.equals(code)){
if(StringUtils.isNotEmpty(msg)){
if(msg.contains(SPLIT)){
String []msgArr = msg.split(SPLIT);
exception = new MyException(msgArr[0], msgArr[1]);
}
}
}
}catch(IOException ex){
log.error(ex.getMessage(), ex);
}
}
}
3.自定义错误捕捉配置
import feign.codec.ErrorDecoder;
import org.springframework.context.annotation.Bean;
public class KeepErrMsgConfiguration{
@Bean
public ErrorDecoder errorDecoder(){
return new MyErrDecoder();
}
}
如果feign.hystrix.enable=true,则@FeignClient(name="serviceProvide", fallback=UserServiceImpl.class)中的fallback会被开启,但是也不会捕获到远端跑出的异常信息,要捕获异常需要使用到fallbackFactory
@FeignClient(name="serviceProvide", fallbackFactory = TestServiceFallback.class)
import feign.hystrix.FallbackFactory;
import org.apache.commons.lang3.StringUtils;
@Component
public class TestServiceFallback implements FallbackFactory<TestService> {
private static final Logger LOG = LoggerFactory.getLogger(TestServiceFallback.class);
public static final String ERR_MSG = "Test接口暂时不可用: ";
@Override
public TestService create(Throwable throwable) {
String msg = throwable == null ? "" : throwable.getMessage();
if (!StringUtils.isEmpty(msg)) {
LOG.error(msg);
}
return new TestService() {
@Override
public String get(Integer id) {
return ResultBuilder.unsuccess(ERR_MSG + msg);
}
};
}
}