MSA에서는 서버간 통신이 자주 일어난다.
서버간 http 통신을 할 때 보통 RestTemplate, WebClient를 사용한다.
ex) RestTemplate 사용
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", "data");
HttpEntity<String> request = new HttpEntity<>(jsonObject.toJSONString(), headers);
Object response = restTemplate.postForEntity("/url", request, Object.class);
요청에 대한 모듈을 만든다 하더라도 헤더 값, body 또는 쿼리스트링 값 세팅을 해주어야 하고 귀찮다.
그럴때 OpenFeign을 사용하면 매우 간단하게 통신이 가능하다.
@FeignClient(name = "test", url = "http://localhost:8080")
public interface AuthWithUrlFeignClient {
@GetMapping("/test")
String ok();
}
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
** 주의 : spring cloud project 이므로 dependencyManagement 추가 해주어야 한다
ext { set('springCloudVersion', "2021.0.4") } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } }
@EnableFeignClients
어노테이션을 붙이면 세팅 끝!@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
GET http://localhost:9000/auth/test/success
를 요청한다.@FeignClient(name = "gateway", url = "${gateway.url}")
public interface AuthWithUrlFeignClient {
@GetMapping("/auth/test/success")
String ok();
}
옵션 | 설명 |
---|---|
url | http://localhost:9000 이렇게 직접 적어도 되고 설정 파일에서 불러와 사용할 수 있다. (${property}) |
application.yml
gateway.url: http://localhost:9000
🧨 유레카에 등록되어있는 서비스간 통신을 할 경우에는 url없이 application name만으로 통신이 가능하다.
@FeignClient(name = "auth-service") public interface AuthFeignClient { ... }
application.yml
spring: application: name: auth-service
public class TestDto {
private String username;
private String password;
}
GET http://<auth-service>/test/success/param?username=user&password=1234
를 요청한다.@FeignClient(name = "auth-service")
public interface AuthFeignClient {
@GetMapping("/test/success/param")
String withQueryString(@RequestParam TestDto request);
}
GET http://<auth-service>/test/success/{value}
를 요청한다.@FeignClient(name = "auth-service")
public interface AuthFeignClient {
@GetMapping("/test/success/{value}")
String withPathVariable(@PathVariable String value);
}
GET http://<auth-service>/test/success/header
를 요청한다.@FeignClient(name = "auth-service")
public interface AuthFeignClient {
@GetMapping("/test/success/header")
String withHeader(@RequestHeader String token);
}
POST http://<auth-service>/test/success
를 요청한다.@FeignClient(name = "auth-service")
public interface AuthFeignClient {
@PostMapping("/test/success")
String withBody(@RequestBody TestDto dto);
}
RequestInterceptor
를 빈으로 등록해 주면 요청하기 전 해당 작업을 추가한다.
public class CustomConfig {
@Bean
public RequestInterceptor requestInterceptor(@Value("${token}") String token) {
return requestTemplate -> requestTemplate.header("token", token);
}
}
GET http://<auth-service>/test/success/header
를 요청한다.CustomConfig
의 인터셉터가 동작한다.@FeignClient(name = "auth-service", configuration = CustomConfig.class)
public interface AuthWithConfigFeignClient {
@GetMapping("/test/success/header")
String withHeader();
}
🧨 주의!
CustomConfig
객체에를 빈으로 등록할 경우에는 모든 FeignClient 인터페이스에서 요청하는 모든 api요청에 해당 설정이 추가된다.@Configuration public class CustomConfig { @Bean public RequestInterceptor requestInterceptor(@Value("${token}") String token) { return requestTemplate -> requestTemplate.header("token", token); } }
ErrorDecoder
를 상속받아 구현한다.
@Slf4j
@Configuration
public class FeignErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
log.info("methodKey => {}", methodKey);
log.info("response => {}", response);
// http status code에 따른 처리
switch (response.status()) {
case 400:
case 404:
break;
default:
throw new RuntimeException("custom exception");
}
return null;
}
}
application.yml
logging:
level:
com.example.api.feign: DEBUG
@Configuration
public class GlobalCustomConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
레벨 | 설명 |
---|---|
NONE | 로깅 X(기본값) |
BASIC | 요청의 메소드 및 url, 응답의 응답코드 및 실행시간 |
HEADERS | 요청과 응답의 헤더와 기본정보 |
FULL | 요청과 응답의 헤더, 바디, 메타데이터 |
설정 | 설명 | 기본값 |
---|---|---|
connectTimeout | 커넥션 연결 대기시간 | 1000 |
readTimeout | 응답 대기 시간 | 60000 |
application.yml
feign:
client:
config:
default:
connectTimeout: 1000
readTimeout: 3000
@Configuration
public class GlobalCustomConfig {
@Bean
public Retryer retryer(){
// 기본값 : 0.1초 간격으로 1초에 한번씩 최대 5번 시도
return new Retryer.Default(100L, SECONDS.toMillis(1L), 5);
}
}