Feign Client 异常处理
1、概览
在 Feign
客户端 中,可以使用 ErrorDecoder
或者 FallbackFactory
来处理异常。
2、Maven 依赖
创建一个 Spring Boot 项目,添加 spring-cloud-starter-openfeign
依赖,该 starter 已经包含了 feign-core
依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.3</version>
</dependency>
如果你想自定义要使用的 feign-core
的版本,你也可以手动在 pom.xml
文件中添加 feign-core
依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>11.9.1</version>
</dependency>
3、使用 ErrorDecoder
处理异常
通过自定义 ErrorDecoder
来处理异常,可以在出现异常时返回自定义的异常。
如下:
public class RetreiveMessageErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
@Override
public Exception decode(String methodKey, Response response) {
ExceptionMessage message = null;
try (InputStream bodyIs = response.body().asInputStream()) {
ObjectMapper mapper = new ObjectMapper();
message = mapper.readValue(bodyIs, ExceptionMessage.class);
} catch (IOException e) {
return new Exception(e.getMessage());
}
switch (response.status()) {
case 400:
return new BadRequestException(message.getMessage() != null ? message.getMessage() : "Bad Request");
case 404:
return new NotFoundException(message.getMessage() != null ? message.getMessage() : "Not found");
default:
return errorDecoder.decode(methodKey, response);
}
}
}
在上述 encoder
中,我们覆盖了默认行为,对不同的异常状态返回了不同的异常。
4、使用 Fallback
处理异常
还可以通过配置 fallback
来处理异常。
先创建一个 FeignClient
,然后配置 fallback
:
@FeignClient(name = "file", url = "http://localhost:8081",
configuration = FeignSupportConfig.class, fallback = FileUploadClientWithFallbackImpl.class)
public interface FileUploadClientWithFallBack {
@PostMapping(value = "/upload-error", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
现在,创建 FileUploadClientWithFallbackImpl
,处理不同异常:
@Component
public class FileUploadClientWithFallbackImpl implements FileUploadClientWithFallBack {
@Override
public String fileUpload(MultipartFile file) {
try {
throw new NotFoundException("hi, something wrong");
} catch (Exception ex) {
if (ex instanceof BadRequestException) {
return "Bad Request!!!";
}
if (ex instanceof NotFoundException) {
return "Not Found!!!";
}
if (ex instanceof Exception) {
return "Exception!!!";
}
return "Successfully Uploaded file!!!";
}
}
}
接着,创建一个简单的测试来验证 fallback
是否生效:
@Test(expected = NotFoundException.class)
public void whenFileUploadClientFallback_thenFileUploadError() throws IOException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
File file = new File(classloader.getResource(FILE_NAME).getFile());
Assert.assertTrue(file.exists());
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
IOUtils.toByteArray(input));
uploadService.uploadFileWithFallback(multipartFile);
}
5、使用 FallbackFactory
处理异常
还可以通过配置 FallbackFactory
来处理异常。
先创建一个 @FeignClient
,然后配置 FallbackFactory
:
@FeignClient(name = "file", url = "http://localhost:8081",
configuration = FeignSupportConfig.class, fallbackFactory = FileUploadClientFallbackFactory.class)
public interface FileUploadClient {
@PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
现在,创建 FileUploadClientFallbackFactory
,处理不同异常:
@Component
public class FileUploadClientFallbackFactory implements FallbackFactory<FileUploadClient> {
@Override
public FileUploadClient create(Throwable cause) {
return new FileUploadClient() {
@Override
public String fileUpload(MultipartFile file) {
if (cause instanceof BadRequestException) {
return "Bad Request!!!";
}
if (cause instanceof NotFoundException) {
return "Not Found!!!";
}
if (cause instanceof Exception) {
return "Exception!!!";
}
return "Successfully Uploaded file!!!";
}
};
}
}
创建测试,验证 FallbackFactory
是否生效:
@Test(expected = NotFoundException.class)
public void whenFileUploadClientFallbackFactory_thenFileUploadError() throws IOException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
File file = new File(classloader.getResource(FILE_NAME).getFile());
Assert.assertTrue(file.exists());
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
IOUtils.toByteArray(input));
uploadService.uploadFileWithFallbackFactory(multipartFile);
}
6、总结
在使用 Feign Client 的时候,你可以通过 ErrorDecoder
或者自定义 fallback
、 fallbackFactory
实现来处理异常。
参考:https://www.baeldung.com/java-feign-client-exception-handling