RestTemplate
token:
expiration_time: 864000000
secret: '{cipher}AQBQMwrjDGVYOUquU1Rgcxs7c+ELCWNwBYcmKD7cH++Vnd7G5+dT0TvfiR/LBMWOBAHgB58+cwPVQKI05u0jzDoHR2MJE/q3DVJuj64x8SWVf/e6qeUM/CQhy8T5Bs8erpplR7p+fd8r7U/B3rpsgQ63mAgtLrpy3c5A9PlTvWFW6/fg+paWKQP6UEv56lqjQIysQhIUwmBDxBAEN0iCKz2g8k/bfClVZXylWLdCtboIgjw4mcbq4zEbJE4o1QHIF73aLK9fwZ9sahmjZSOYVYJcNjVCRLI7iHFBI4BQWGzids/9l/m77GG3zbdEzTAE5G1PCjnBm2No+rcj1GPUPswg1O9I9UI7EAzuHBXdG+lpJUJHxer7TPirWjmfCcucBCKrsRsZm2PtkTsVUqjzbCoh'
gateway:
ip: localhost
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:~/test
username: '{cipher}AQCpRg9qo8u0WDkdlZXUK2AJ6k+MtBI/hYHS/uUJlDfmtjObQksSkvLRL3wrXafBZsnnIE0e8cnXnPb9QPpdoKkBWFftMTMkTZlMfB7XpIW/Ov4qlGcvxyscgsO+Je5vuF1OwgdiieEA4Axy1P0hh7+A48hfdusyoNui3U6lMB0z1x5WDLuvbbeioHhgucgKZfdgpkt9ulR6hAVgbigDMyOFFtiyyPWH+B/p31AtMZWGkyt7gwNY/JuUBbVSdI+5ysV8bP+UqK6OvG6yQUT2020bjvckprr7pz4xn+ni2ZtReznXwz+2Gz0LMm0PbdpMpOsztxYyLjF/exRK3E+3S3KEYzw+c/GgjaPq+xUAe30OuAWPHztlcR4lqijxJ/mSlcg='
order_service:
# url: http://localhost:8000/order-service/%s/orders
url: http://ORDER-SERVICE/order-service/%s/orders
String orderUrl = String.format(env.getProperty("order_service.url"),userId);
ResponseEntity<List<ResponseOrder>> orderListResponse = restTemplate.exchange(orderUrl, HttpMethod.GET,
null, new ParameterizedTypeReference<List<ResponseOrder>>() {
});
user service 에서 order service를 restTemplate을 통해 호출하는 상황이다.
user service가 참조하는 설정에서 url 이 ORDER-SERVICE가 되어있는데 이는
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@LoadBalanced 덕분에 Eureka server를 참조해서 어떤 ms 로 가야하고 그 주소를 알수 있게 된다.
통상적으로 client 의 첫 요청은 gateway를 지나면서 검증을 받고 그 이후 ms끼리 비지니스 로직을 처리하기 위해서 소통할때는 gateway를 거치지 않는다고 한다.
Feign Client
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserServiceApplication {
main 함수 가 존재하는 클래스위에다 @EnableFeignClients를 명시해줘야 사용할 interface에 구현체를 만들어서 빈으로 주입해준다.
호출 하려는 HTTP Endpoint 에 대한 interface 생성 후 @FeignClient 선언을 해준다.
@FeignClient(name="order-service")
public interface OrderServiceClient {
@GetMapping("/order-service/{userId}/orders")
List<ResponseOrder> getOrders(@PathVariable String userId);
}
따로 호출할 ms의 함수 시그니쳐와 인터페이스를 선언을 한후에 OrderServiceClient를 주입받으면
아래처럼 사용이 가능해진다.
/*
Using FeignClient
*/
List<ResponseOrder> ordersList = orderServiceClient.getOrders(userId);
userDto.setOrders(ordersList);
Restemplate 보다 코드가 훨씬 간결해졌다.
Feign Client 예외처리
log level을 DEUBG로 해준후에
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
이렇게 빈으로 등록을 해주면
아래와 같이 HTTP Trace 정보를 보여준다. 현재 user -> order 로 가는 url 이 잘못되어서 status는 500 에러이지만 404가 중간에 뜬 진짜 에러이다.
List<ResponseOrder> ordersList = null;
try {
ordersList = orderServiceClient.getOrders(userId);
} catch (FeignException exception) {
log.error(exception.getMessage());
}
2022-10-28 15:08:06.992 ERROR 30683 --- [o-auto-1-exec-3] c.e.userservice.service.UserServiceImpl : [404] during [GET] to [http://order-service/order-service/d4788410-8dea-471e-8e8f-2aa3cfc7b295/orders_ng] [OrderServiceClient#getOrders(String)]: [{"timestamp":"2022-10-28T06:08:06.985+00:00","status":404,"error":"Not Found","message":"No message available","path":"/order-service/d4788410-8dea-471e-8e8f-2aa3cfc7b295/orders_ng"}]
위와 같이 Exception 을 잡아주면 로그를 띄워주고 정상적으로 처리가 된다.
원래 출력되던 error trace가 출력되지 않은것을 확인 할 수 있다.
또한 우리가 Feign Client에서 호출할 url 을 엉뚱한 것을 지정해서 내부적으로 404 에러가 떴지만 gateway를 거쳐 client단에는 우리가 내부적인 서버에러인 500 status code를 준것을 확인할 수 있다. 이것은 좋지 않다.
FeignErrorDecoder
@RequiredArgsConstructor
@Component
public class FeignErrorDecoder implements ErrorDecoder {
private final Environment env;
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()) {
case 400:
break;
case 404:
if (methodKey.contains("getOrders")) {
return new ResponseStatusException(HttpStatus.valueOf(response.status()),
env.getProperty("order_service.exception.orders_is_empty"));
}
break;
default:
return new Exception(response.reason());
}
return null;
}
}
List<ResponseOrder> ordersList = orderServiceClient.getOrders(userId);
userDto.setOrders(ordersList);
기존에는 try catch로 order service 호출에 대한 에러 대비를 했었지만 FeignErrorDecoder를 빈으로 등록 해 놓으면 FeignClient를 통해 다른 ms 호출시에 response에 알맞게 에러를 처리해준다.
500번에러가 아니라 404 notfound 라는 좀 더 제대로 된 에러를 뿜게되는것을 확인할 수 있다.
@FeignClient(name="catalog-service", configuration = FeignErrorDecoder2.class)
public interface CatalogServiceClient {
또한 여러 Feign Client를 사용시에 각각 맞는 Decoder를 위와 같이 등록해 줄 수 있다.
'Cloud > SpringCloud로 개발하는 MSA' 카테고리의 다른 글
MS간의 data 동기화 (2. kafka 응용) (1) | 2022.11.03 |
---|---|
MS간의 data 동기화 (1. kafka 기본 이론) (0) | 2022.11.02 |
gateway 인증 + Cloud Config + Cloud Bus(rabbitMQ) + 암호화 (0) | 2022.10.28 |
API Gateway Service (0) | 2022.10.14 |
Service Discovery (0) | 2021.06.29 |