
Feign Client는 Spring Cloud에서 제공하는 HTTP 클라이언트로, RestTemplate이나 WebClient보다 간결한 방식으로 API 호출을 수행할 수 있습니다. Feign Client를 활용한 API 호출 방식과 예외 처리 방법을 예제와 함께 설명하겠습니다.
1. Feign Client란?
Feign은 Java에서 REST API를 쉽게 호출할 수 있도록 도와주는 HTTP 클라이언트입니다. 인터페이스 기반으로 RESTful API를 호출할 수 있어, 기존 RestTemplate을 사용할 때보다 코드량을 줄일 수 있습니다.
2. Feign Client 설정 및 구현
인터페이스 정의
@FeignClient(name = "apiClient", url = "http://example.com", configuration = FeignClientConfig.class)
public interface ApiClient {
@GetMapping("{endpoint}")
ResponseEntity fetchData(@RequestParam Map<string, object=""> params, @PathVariable String endpoint);
@PostMapping("{endpoint}")
ResponseEntity sendData(@RequestBody Map<string, object=""> payload, @PathVariable String endpoint);
}
Feign Client를 호출하는 서비스 구현
@Service
public class ApiService {
private final FeignClientBuilder clientBuilder;
public ApiService(ApplicationContext appContext) {
this.clientBuilder = new FeignClientBuilder(appContext);
}
private Map<String, Object> handleResponse(ResponseEntity<?> responseEntity) {
Map<String, Object> body = JsonUtil.parse(responseEntity.getBody(), new TypeReference<Map<String, Object>>() {});
boolean success = (boolean) body.get("success");
if (!success) {
if (Integer.parseInt(body.get("code").toString()) < 500) {
throw new BusinessException(body.get("message").toString());
} else {
throw new RuntimeException("서버 오류 발생");
}
}
return JsonUtil.parse(body.get("data"), new TypeReference<Map<String, Object>>() {});
}
public Map<String, Object> getData(RequestDto requestDto) {
ApiClient client = clientBuilder.forType(ApiClient.class, requestDto.getService()).build();
ResponseEntity<?> responseEntity = client.fetchData(requestDto.getParams(), requestDto.getEndpoint());
return handleResponse(responseEntity);
}
public Map<String, Object> postData(RequestDto requestDto) {
ApiClient client = clientBuilder.forType(ApiClient.class, requestDto.getService()).build();
ResponseEntity<?> responseEntity = client.sendData(requestDto.getParams(), requestDto.getEndpoint());
return handleResponse(responseEntity);
}
}
3. Feign 예외 처리 (ErrorDecoder)
Feign을 사용할 때 HTTP 오류 응답 (4xx, 5xx) 에 대해 적절한 예외 처리를 위해 ErrorDecoder를 구현합니다.
@Slf4j
@NoArgsConstructor
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
log.error("{} 요청이 실패했습니다. 상태 코드: {}, URL: {}, 응답 본문: {}",
methodKey, response.status(), response.request().url(), ResponseUtil.getResponseBody(response));
if (shouldRetry(response)) {
return new RetryableException(0, String.format("%s 요청 실패 - 재시도 합니다. 상태: %s", methodKey, response.status()), null, null, null);
}
return new IllegalStateException(String.format("%s 요청 실패 - 상태: %s", methodKey, response.status()));
}
private boolean shouldRetry(Response response) {
return response.request().httpMethod().toString().equalsIgnoreCase("GET") &&
(response.status() >= 500 || response.status() == 429);
}
}
4. Feign 요청 및 응답 로깅
Feign 요청 및 응답 데이터를 로깅할 수 있도록 ResponseUtil 유틸 클래스를 작성하였습니다.
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ResponseUtil {
public static String getRequestBody(Response response) {
if (response.request().body() == null) {
return "";
}
try {
return new String(response.request().body(), StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
log.error("Feign 요청 바디 변환 오류", e);
return "";
}
}
public static String getResponseBody(Response response) {
if (response.body() == null) {
return "";
}
try (InputStream responseBodyStream = response.body().asInputStream()) {
return IOUtils.toString(responseBodyStream, StandardCharsets.UTF_8.name());
} catch (IOException e) {
log.error("Feign 응답 바디 변환 오류", e);
return "";
}
}
}
5. Feign Client 설정 (FeignClientConfig)
Feign Client의 타임아웃 및 로깅을 설정하기 위해 FeignClientConfig 클래스를 작성하였습니다.
@Configuration
public class FeignClientConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public Request.Options requestOptions() {
return new Request.Options(5000, 10000);
}
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}

Feign Client를 활용하면 API 호출을 더욱 간결하게 작성할 수 있으며, ErrorDecoder와 ResponseUtil을 활용하여 예외 처리를 할 수 있습니다. 마이크로서비스 환경에서는 서비스 간 통신이 많기 때문에, Feign을 잘 활용하면 좋습니다.
'프로젝트 > 마이그레이션' 카테고리의 다른 글
JWT 토큰을 쿠키에 저장하여 인증 처리하기 (0) | 2025.03.13 |
---|---|
Spring AOP를 활용한 로깅(Log) 설정 (1) | 2025.02.04 |
Spring AOP를 활용한 트랜잭션 관리 설정 (1) | 2025.02.04 |
스프링에서 전략 패턴(Strategy Pattern) 활용하기 (2) | 2025.02.03 |
Spring BeanNameGenerator 구현 (3) | 2025.01.24 |