리버스 프록시는 요청을 대신해서 보내는 것이다. 클라이언트의 요청을 받아 적절한 웹 서버로 요청을 전송한다. 요청을 받은 서버는 응답을 전송할 떄, 다시 이 리버스 프록시에게 전달하여 그 응답을 클라이언트에게 제공한다.
대표적으로는 nginx가 우리가 잘 알고있는 리버스 프록시 서버이다.
RestTemplate restTemplate = new RestTemplate();
restTemplate.getForObject("http://localhost:8080/", User.class, 200);
@FeignClient("stores")// 호출하고 싶은 마이크로 서비스 명 작성public interface StoreClient {
@GetMapping("/stores")
List<Store> getStores();
}
@Configuration
public class FilterConfig {
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/first-service/**")
.filters(f -> f.addRequestHeader("first-request", "first-request-header")
.addResponseHeader("first-response", "first-response-header"))
.uri("http://localhost:8081"))
.route(r -> r.path("/second-service/**")
.filters(f -> f.addRequestHeader("second-request", "second-request-header")
.addResponseHeader("second-response", "second-response-header"))
.uri("http://localhost:8082"))
.build();
}
}
server:
port: 8080
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
uri: http://localhost:8081/
predicates:
- Path=/first-service/**
filters:
- AddRequestHeader=first-request, first-request-header-withyml
- AddResponseHeader=first-response, first-response-header-withyml
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- AddRequestHeader=second-request, second-request-header-withyml
- AddResponseHeader=second-response, second-response-header-withyml
개인적으로는 자바코드로 설정하는 것이 훨씬 나아보인다. 컴파일로 내가 잘못 작성했을 경우 에러가 발생하기 때문에!
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter() {
super(Config.class);
}
public static class Config {
// Put the configuration properties
}
@Override
public GatewayFilter apply(Config config) {
// Custom Prefilterreturn (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Custom Pre filter : request id -> {}", request.getId());
// Custom Postfilterreturn chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
log.info("Custom Post filter : response statusCode -> {}", response.getStatusCode());
}));
};
}
}
각 라우팅 정보마다 커스터마이징한 필터를 등록해주어야 한다. 앞에서 설정했던 Custom Filter가 그렇다. 하지만 Global Filter의 경우 라우팅 정보들 마다 공통적으로 필요한 처리들을 한번의 설정으로 해결해준다.
둘 다 적용되었을 경우의 순서 : Global Filter PRE -> Custom Filter PRE -> Custom Filter POST -> Global Filter POST
server:
port: 8080
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
# Global Filter 설정하기default-filters:
- name: GlobalFilter# 클래스명args:
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service
uri: http://localhost:8081/
predicates:
- Path=/first-service/**
filters:
- CustomFilter
# - AddRequestHeader=first-request, first-request-header-withyml# - AddResponseHeader=first-response, first-response-header-withyml- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- CustomFilter
# - AddRequestHeader=second-request, second-request-header-withyml# - AddResponseHeader=second-response, second-response-header-withyml
Api Gateway에서는 로깅을 위한 필터도 존재하는데, 여기서 로깅 필터도 Custom Filter라서 마이크로 서비스 마다 등록을 해주어야 한다. 강의 내용 처럼 second-service에 등록하자.
이 Logging Filter를 등록하게 되면 요청에 대한 흐름은 다음과 같다.
기본적으로 라운드 로빈 방식으로 각 마이크로서비스를 한번씩 호출한다.
API Gateway에서uri에 lb://서비스명 이라고 설정해두었는데, 이 때 랜덤포트로 설정한 경우는 서비스 명으로 게이트웨이에서 인스턴스를 찾아 각 서비스를 한번씩 호출한다.
설정에 따라 랜덤하게 서버 인스턴스를 호출할 수 있다.
출처