SpringCloud- Gateway
Gateway
Gatewayは非同期機能も提供しています.Zuulは2.4以降でのみ使用可能です.
Lombok, Gateway, Eureka Discovery Client
server:
port: 8000
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/**
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
@RequestMapping("/") 을 아래와 같이 수정
@RequestMapping("/first-service")
上記の変更は、Gatewayが呼び出し後に呼び出されるように設定されているため、上記の変更が必要である.フィルタの適用
1.Java設定フィルタを使用する
...
spring:
application:
name: apigateway-service
# cloud:
# gateway:
# routes:
# - id: first-service
# uri: http://localhost:8081/
# predicates:
# - Path=/first-service/**
# - id: second-service
# uri: http://localhost:8082/
# predicates:
# - Path=/second-service/**
package com.example.apiatewayservice.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
/**
* RouteLocator를 반환해야 application.yml에서 설정한 것처럼 라우터 역할을 함
* RouteLocatorBuilder 인자로 받아 빌더를 라우트 설정 후 리턴
*
* 각각의 route path와 uri로 라우트 시키며 중간 filter를 거침
* first-request 헤더에 first-request-header값을
* first-response 헤더에 first-response-header값을 넣는다.
*/
@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();
}
}
@GetMapping("/message")
public String message(@RequestHeader("first-request") String header){
log.info(header);
return "Hello World in First service";
}
上のfirst-serviceのようにsecond-serviceも同じです.
2.ymlを使用してフィルタを設定する
server:
port: 8000
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-header2
- AddResponseHeader=first-response, first-response-header2
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- AddRequestHeader=second-request, second-request-header2
- AddResponseHeader=second-response, second-response-header2
3.Custom Filterの適用
package com.example.apiatewayservice.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// Custom Pre Filter
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Custom PRE Filter: request id -> {}", request.getId());
// Custom Post Filter
// Mono : 웹 플럭스에서 지원함. 비동기 방식에서 사용
// 내가 reactor 공부한거 참고!! 깃에 있음!
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("Custom POST Filter: response code -> {}", response.getStatusCode());
}));
};
}
public static class Config{
// config 정보를 집어 넣을 수 있음.
}
}
server:
port: 8000
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-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
@GetMapping("/check")
public String check(){
return "Hi, there. this is a message from Fist Service";
}
4.グローバルフィルタの設定
サービスグローバルに対応するフィルタを作成できます.
1.グローバルフィルタの作成
package com.example.apiatewayservice.filter;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
public GlobalFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// Custom Pre Filter
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Global Filter baseMessage: {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Global Filter Start: request id -> {}", request.getId());
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Global Filter End: response code -> {}", response.getStatusCode());
}
}));
};
}
@Getter
@Setter
public static class Config{
// config 정보를 집어 넣을 수 있음.
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
}
server:
port: 8000
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-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
default-filters:
- name: GlobalFilter
args: # Global Filter 내 inner Class의 Config class 에 값이 들어감.
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
5.ログフィルタの設定
package com.example.apiatewayservice.filter;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class LoggingFilter extends AbstractGatewayFilterFactory<LoggingFilter.Config> {
public LoggingFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
/**
* webflux에서
* ServerWebExchange exchange 에 request, response가 있음
* GatewayFilterChain chain은 다양한 필터 프리 필터,포스트 필터, 프리체인 등
*
* OrderedGatewayFilter를 생성하여 우선순위(Order) 설정 가능
* Ordered.HIGHEST_PRECEDENCE : HIGHEST라서 가장 먼저 실행 가능
* LOWEST_PRECEDENCE : HIGHEST_PRECEDENCE의 반대
*/
GatewayFilter filter = new OrderedGatewayFilter((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Logging Filter baseMessage: {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Logging Filter Start: request id -> {}", request.getId());
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Logging Filter End: response code -> {}", response.getStatusCode());
}
}));
}, Ordered.HIGHEST_PRECEDENCE);
return filter;
}
@Getter
@Setter
public static class Config{
// config 정보를 집어 넣을 수 있음.
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
}
server:
port: 8000
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-header2
# - AddResponseHeader=first-response, first-response-header2
- name: CustomFilter
- name: LoggingFilter # 만약에 args를 넣어야한다면 filters 내에 name: 을 앞에 추가해서 구분해줘야함.
args:
baseMessage: Hi, there
preLogger: true
postLogger: true
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
default-filters:
- name: GlobalFilter
args: # Global Filter 내 inner Class의 Config class 에 값이 들어감.
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
Load Banancer-Eureka連動
1.apigate-service,first-service,second-serviceのpom。xml eureka-クライアントのチェックなし
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.apiGateway-サービス、first-service、second-serviceの応用。ymlユリカの設定を変更するには:
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
3.apiGateway-サービスのspring-cloud-ルーティングuriの変更
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
uri: lb://MY-FIRST-SERVICE
predicates: # 조건절
- Path=/first-service/**
filters: # 첫번째 키, 두번째 값
# - AddRequestHeader=first-request, first-request-header2
# - AddResponseHeader=first-response, first-response-header2
- name: CustomFilter
- name: LoggingFilter # 만약에 args를 넣어야한다면 filters 내에 name: 을 앞에 추가해서 구분해줘야함.
args:
baseMessage: Hi, there
preLogger: true
postLogger: true
- id: second-service
uri: lb://MY-SECOND-SERVICE
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
http://localhost:8081/first-serivce/**->lb://MY-FIRST-SERVICE(ユリカでのサービス名)http://localhost:8081/->lb://MY-SECOND-SERVICE
4.first-service,second-service各2個!
server:
port: 0
spring:
application:
name: my-first-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
@GetMapping("/check")
public String check(HttpServletRequest request){
log.info("Server port = {}", request.getServerPort());
return String.format("Hi, there. there is a message from Fist Service on Port %s",
environment.getProperty("local.server.port"));
}
/checkを呼び出すと、ポートごとに1回繰り返し呼び出されます!
Reference
この問題について(SpringCloud- Gateway), 我々は、より多くの情報をここで見つけました https://velog.io/@jae_cheol/SpringCloud-Gatewayテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol