Cloud/MSA

[MSA] Spring Cloud Gateway

문승주 2024. 6. 29. 15:50
반응형

본 내용은 인프런의 이도원 님의 강의 "Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)" 내용을 바탕으로 정리한 내용입니다.

Spring Cloud Gateway란?

  • Spring Reactive 생태계에 구현된 API Gateway로 이 서비스는 논블로킹 (non-blocking), 비동기 (Asynchronous) 방식의 Netty Server를 사용하여 규모와 관계없이 REST 및 WebSocket API를 생성, 게시, 유지, 모니터링 및 보호하는 역할을 한다.

Predicate

  • 요청을 어떤 경로로 라우팅할지 결정하는데 사용되는데 Pre Filter와 Post Filter 의 역할을 수행한다.
  • Pre Filter
    • 메소드가 실행되기 전에 요청에 대한 사전 조건을 검증한다.
  • Post Filter
    • 메소드의 실행을 멈추지 않지만 실행이 완료된 후에 요청에 대한 사후 조건을 검증한다.

Spring Cloud Gateway의 역활

RESTful API 생성

  • HTTP 기반의 상태 비저장 클라이언트-서버 통신을 활성화하며 표준 HTTP 메서드 (GET, POST, PUT, PATCH, DELETE)를 구현한다.

WebSocket API 생성

  • 클라이언트와 서버 간에 상태를 저장하는 전이중 통신을 지원하며 수신 메시지를 메시지 콘텐츠에 따라 라우팅한다.

Spring Cloud Gateway 구현

GateWayService-Project 생성

  • Spring Boot : 3.2.7-SNAPSHOT
  • Java : 11
  • Project Name : gateway-service
  • Dependencies : DevTools, Eureka Discovery Client, Gateway

1. Java 코드로 구현

GateWayService-Project 코드

application.yml

server:  
  port: 8080  

spring:  
  application:  
    name: gateway-service

eureka:  
  client:  
    register-with-eureka: false  
    fetch-registry: false  
    service-url:  
      defaultZone: http://localhost:8761/eureka
  • eureka.client.register-with-eureka: false : 애플리케이션은 Eureka 서버에 자신을 등록하지 않는다.
  • eureka.client.fetch-registry: false : 애플리케이션은 Eureka 서버에서 다른 서비스의 정보를 가져오지 않는다.
  • eureka.client.service-url.defaultZone: http://localhost:8761/eureka : 애플리케이션은 Eureka 서버를 http://localhost:8761/eureka에서 찾는다.
FilterConfig
  • 자바코드를 사용하여 특정 URI 요청 시 필터 작업을 한다.
package com.example.gateway_service.filter;  

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 {  

    /**  
     * first-service나 second-service 호출시 필터작업  
     * RequestHeader와 ResponseHeader에 값을 추가  
     * @param builder  
     * @return  
     */  
    @Bean  
    public RouteLocator gatewayRoutes(RouteLocatorBuilder builder){  
        return builder.routes()  
                .route(r -> r.path("/first-service/**")  
                        .filters(f -> f.addRequestHeader("first-request","first-request-header")  
                                .addRequestHeader("first-response", "first-response-header"))  
                        .uri("http://localhost:8081/"))  
                .route(r -> r.path("/second-service/**")  
                        .filters(f -> f.addRequestHeader("second-request","second-request-header")  
                                .addRequestHeader("second-response", "second-response-header"))  
                        .uri("http://localhost:8082/"))  
                .build();  
    }  
}
  • `/first-service/`로 들어오는 요청**
    • 요청 헤더에 first-request: first-request-header를 추가한다.
    • 응답 헤더에 first-response: first-response-header를 추가한다.
    • 요청을 http://localhost:8081/로 전달한다.
  • `/second-service/`로 들어오는 요청**
    • 요청 헤더에 second-request: second-request-header를 추가한다.
    • 응답 헤더에 second-response: second-response-header를 추가한다.
    • 요청을 http://localhost:8082/로 전달한다.

FirstService-Project / SecondService-Project 수정

  • uri 뒤에 Path 가 붙여서 호출되므로 @RequestMapping에 **-service를 추가해야 된다.
  • 필터 작업에 따른 message 헤더 추가
FirstServiceController
package com.example.firstservice.controller;  

import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RequestHeader;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  

@RestController  
@RequestMapping("/first-service")  
public class FirstServiceController {  

    @GetMapping("/welcome")  
    public String welcome() {  
        return "Welcome to the First service.";  
    }  

    @GetMapping("/message")  
    public String message(@RequestHeader("first-request") String header) {  
        System.out.println(header);  
        return "Hello World in First Service";  
    }
}
SecondServiceController
package com.example.secondservice.controller;  

import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RequestHeader;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  

@RestController  
@RequestMapping("/second-service")  
public class SecondServiceController {  

    @GetMapping("/welcome")  
    public String welcome() {  
        return "Welcome to the Second service.";  
    }  

    @GetMapping("/message")  
    public String message(@RequestHeader("second-request") String header) {  
        System.out.println(header);  
        return "Hello World in Second Service";  
    }  
}
  • 요청 헤더와 응답 헤더에 필터에서 추가한 값이 포함됩니다.

결과

그림 1) first-reponse-header 값이 ResponseHeaders에 추가되고 second-service도 second-reponse-header 값이 ResponseHeaders에 추가된다.

2. yml 파일로 구현

GateWayService-Project 코드

  • FilterConfig 파일 삭제
    application.yml
server:  
  port: 8080  

eureka:  
  client:  
    register-with-eureka: false  
    fetch-registry: false  
    service-url:  
      defaultZone: http://localhost:8761/eureka  

spring:  
  application:  
    name: gateway-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
  • Java 코드 대신 application.yml에 경로, 필터, 헤더 등을 정의.
  • 동일한 필터 동작을 yml 설정으로 처리.

결과

그림 2) Postman에서 요청 후 응답헤더에 설정한 필터 first-response-header2 값 확인

Java vs yml 비교

구현 방식 특징
Java 코드로 설정 동적인 라우팅 로직 구현 가능. 복잡한 조건과 커스터마이징에 적합.
yml 파일로 설정 간단한 설정과 유지보수에 적합. 코드 분리를 통해 가독성과 간결성을 유지.

 

반응형