Spring Cloud Gateway: новое поколение сервисов шлюза API

Spring Cloud
Spring Cloud Gateway: новое поколение сервисов шлюза API

Адрес фактического проекта электронной коммерции SpringBoot (20k+star):GitHub.com/macro-positive/…

Резюме

Spring Cloud Gateway обеспечивает поддержку шлюза API для приложений SpringBoot с мощными интеллектуальными функциями маршрутизации и фильтрации.В этой статье будет подробно рассказано о его использовании.

Введение в шлюз

Gateway — это служба шлюза API, созданная на основе экосистемы Spring и основанная на таких технологиях, как Spring 5, Spring Boot 2 и Project Reactor. Шлюз призван предоставить простой и эффективный способ маршрутизации API, а также предоставить некоторые мощные функции фильтрации, такие как: автоматический выключатель, ограничение тока, повторная попытка и т. д.

Spring Cloud Gateway имеет следующие функции:

  • Построен на Spring Framework 5, Project Reactor и Spring Boot 2.0;
  • Динамическая маршрутизация: возможность сопоставления любого атрибута запроса;
  • Для маршрутов можно указать Predicate и Filter;
  • Интегрируйте функцию автоматического выключателя Hystrix;
  • Интеграция функции обнаружения службы Spring Cloud;
  • Простой в написании предикат и фильтр;
  • Функция ограничения тока запроса;
  • Перезапись пути поддерживается.

Связанные концепции

  • Маршрут (Маршрут): Маршрут является основным модулем для построения шлюза.Он состоит из идентификатора, целевого URI, ряда утверждений и фильтров.Если утверждение истинно, маршрут соответствует;
  • Предикат: относится к предикату функции Java 8. Тип ввода — ServerWebExchange в среде Spring. Это позволяет разработчикам сопоставлять все в HTTP-запросе, например заголовки или параметры запроса. Маршрутизировать, если запрос соответствует утверждению;
  • Фильтр (filter): относится к экземпляру GatewayFilter в среде Spring.Используя фильтр, запрос можно изменить до и после маршрутизации запроса.

Создайте модуль API-шлюза

Здесь мы создаем модуль API-шлюза, чтобы продемонстрировать общие функции шлюза.

Добавьте связанные зависимости в pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

Два разных способа настройки маршрутизации

Шлюз предоставляет два разных способа настройки маршрутизации: один — через файл yml, другой — через Java Bean, мы представим их отдельно ниже.

Использовать yml-конфигурацию

  • Настройте в application.yml:
server:
  port: 9201
service-url:
  user-service: http://localhost:8201
spring:
  cloud:
    gateway:
      routes:
        - id: path_route #路由的ID
          uri: ${service-url.user-service}/user/{id} #匹配后路由地址
          predicates: # 断言,路径相匹配的进行路由
            - Path=/user/{id}
  • Запустите службы eureka-server, user-service и api-gateway и вызовите адресный тест:http://localhost:9201/user/1

  • Мы обнаружили, что запрос был перенаправлен на путь user-service:http://localhost:8201/user/1

Конфигурация с использованием Java Beans

  • Добавьте связанные классы конфигурации и настройте объект RouteLocator:
/**
 * Created by macro on 2019/9/24.
 */
@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route2", r -> r.path("/user/getByUsername")
                        .uri("http://localhost:8201/user/getByUsername"))
                .build();
    }
}

Использование предиката маршрута

Spring Cloud Gateway реализует сопоставление маршрутов как часть инфраструктуры Spring WebFlux HandlerMapping. Spring Cloud Gateway включает ряд встроенных фабрик предикатов маршрутов. Все эти предикаты соответствуют различным атрибутам HTTP-запроса. Несколько фабрик предикатов маршрутов могут быть объединены Давайте представим некоторые часто используемые предикаты маршрутов.

Примечание. Конфигурация, указанная в Predicate, изменяется в файле application-predicate.yml, и служба API-шлюза запускается с этой конфигурацией.

After Route Predicate

Запросы после указанного времени будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: ${service-url.user-service}
          predicates:
            - After=2019-09-24T16:30:00+08:00[Asia/Shanghai]

Before Route Predicate

Запросы до указанного времени будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Before=2019-09-24T16:30:00+08:00[Asia/Shanghai]

Between Route Predicate

Запросы в течение указанного интервала времени будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Between=2019-09-24T16:30:00+08:00[Asia/Shanghai], 2019-09-25T16:30:00+08:00[Asia/Shanghai]

Cookie Route Predicate

Запросы с указанным файлом cookie будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: ${service-url.user-service}
          predicates:
            - Cookie=username,macro

Используйте инструмент curl, чтобы отправить файл cookie какusername=macroзапросы могут соответствовать этому маршруту.

curl http://localhost:9201/user/1 --cookie "username=macro"

Header Route Predicate

Запросы с указанными заголовками будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: ${service-url.user-service}
        predicates:
        - Header=X-Request-Id, \d+

Используйте инструмент curl для отправки заголовков запроса в видеX-Request-Id:123запросы могут соответствовать этому маршруту.

curl http://localhost:9201/user/1 -H "X-Request-Id:123" 

Host Route Predicate

Запросы с указанным Хостом будут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: ${service-url.user-service}
          predicates:
            - Host=**.macrozheng.com

Используйте инструмент curl для отправки заголовков запроса в видеHost:www.macrozheng.comзапросы могут соответствовать этому маршруту.

curl http://localhost:9201/user/1 -H "Host:www.macrozheng.com" 

Method Route Predicate

Отправка запроса на указанный метод будет соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: ${service-url.user-service}
        predicates:
        - Method=GET

Этот маршрут можно сопоставить, отправив запрос GET с помощью инструмента curl.

curl http://localhost:9201/user/1

Отправка запроса POST с помощью инструмента curl не может соответствовать этому маршруту.

curl -X POST http://localhost:9201/user/1

Path Route Predicate

Отправка запроса по указанному пути будет соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: ${service-url.user-service}/user/{id}
          predicates:
            - Path=/user/{id}

Отправить с помощью инструмента завиток/user/1Запросы пути могут соответствовать этому маршруту.

curl http://localhost:9201/user/1

Отправить с помощью инструмента завиток/abc/1Запрос маршрута не может соответствовать маршруту.

curl http://localhost:9201/abc/1

Query Route Predicate

Запросы с указанными параметрами запроса могут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: ${service-url.user-service}/user/getByUsername
        predicates:
        - Query=username

Отправьте ленту с помощью инструмента скручиванияusername=macroЗапросы с параметрами запроса могут соответствовать этому маршруту.

curl http://localhost:9201/user/getByUsername?username=macro

Отправка запроса с параметрами запроса или без них с помощью инструмента curl не может соответствовать этому маршруту.

curl http://localhost:9201/user/getByUsername

RemoteAddr Route Predicate

Запросы, исходящие с указанного удаленного адреса, могут соответствовать этому маршруту.

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: ${service-url.user-service}
        predicates:
        - RemoteAddr=192.168.1.1/24

Использование инструмента curl для инициирования запроса от 192.168.1.1 может соответствовать этому маршруту.

curl http://localhost:9201/user/1

Weight Route Predicate

Используйте вес для маршрутизации соответствующего запроса, следующее означает, что 80 % запросов будут перенаправлены на локальный хост: 8201, а 20 % — на локальный хост: 8202.

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: http://localhost:8201
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: http://localhost:8202
        predicates:
        - Weight=group1, 2

Использование фильтра маршрута

Фильтры маршрутов можно использовать для изменения входящих HTTP-запросов и возвращаемых HTTP-ответов.Фильтры маршрутов можно использовать только путем указания маршрутов. Spring Cloud Gateway имеет множество встроенных фильтров маршрутизации, все из которых генерируются фабричным классом GatewayFilter. Давайте представим использование общих фильтров маршрутизации.

AddRequestParameter GatewayFilter

Фильтр, добавляющий параметры к запросу.

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: http://localhost:8201
          filters:
            - AddRequestParameter=username, macro
          predicates:
            - Method=GET

Приведенная выше конфигурация добавит к запросу GETusername=macroПараметры запроса проверяются инструментом curl с помощью следующей команды.

curl http://localhost:9201/user/getByUsername

Эквивалентно инициированию запроса:

curl http://localhost:8201/user/getByUsername?username=macro

StripPrefix GatewayFilter

Фильтр, который удаляет указанное количество префиксов пути.

spring:
  cloud:
    gateway:
      routes:
      - id: strip_prefix_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - StripPrefix=2

Вышеупомянутая конфигурация начнется с/user-service/Удалите две цифры из пути запроса в начале и используйте следующую команду, чтобы проверить его с помощью инструмента curl.

curl http://localhost:9201/user-service/a/user/1

Эквивалентно инициированию запроса:

curl http://localhost:8201/user/1

PrefixPath GatewayFilter

В отличие от фильтра StripPrefix, фильтр, добавляющий операции к исходному пути.

spring:
  cloud:
    gateway:
      routes:
      - id: prefix_path_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - PrefixPath=/user

Приведенная выше конфигурация добавит ко всем запросам GET/userПрефикс пути, проверенный с помощью следующей команды с помощью инструмента curl.

curl http://localhost:9201/1

Эквивалентно инициированию запроса:

curl http://localhost:8201/user/1

Hystrix GatewayFilter

Фильтры Hystrix позволяют добавлять функции прерывателя цепи к маршрутам шлюза, изолировать ваши службы от каскадных сбоев и обеспечивать обработку деградации службы.

  • Чтобы включить функцию прерывателя цепи, нам нужно добавить соответствующие зависимости Hystrix в pom.xml:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • Затем добавьте соответствующий класс обработки перехода на более раннюю версию службы:
/**
 * Created by macro on 2019/9/25.
 */
@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Object fallback() {
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","Get request fallback!");
        result.put("code",500);
        return result;
    }
}
  • Добавьте соответствующую конфигурацию в application-filter.yml, и при возникновении ошибки маршрутизации она будет перенаправлена ​​на контроллер для обработки понижения службы:
spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback
  • Закройте пользовательский сервис и вызовите этот адрес для тестирования:http://localhost:9201/user/1обнаружено, что была возвращена информация об обработке ухудшения обслуживания.

RequestRateLimiter GatewayFilter

Для ограничения потока можно использовать фильтр RequestRateLimiter. Используйте реализацию RateLimiter, чтобы определить, следует ли разрешить продолжение текущего запроса. Если запрос слишком велик, он по умолчанию возвращает статус HTTP 429-Too Many Requests.

  • Добавьте связанные зависимости в pom.xml:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
  • Добавьте класс конфигурации текущей политики ограничения.Здесь есть две стратегии: одна — ограничить ток в соответствии с именем пользователя в параметре запроса, а другая — ограничить ток в соответствии с IP-адресом доступа;
/**
 * Created by macro on 2019/9/25.
 */
@Configuration
public class RedisRateLimiterConfig {
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
    }

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}
  • Мы используем Redis для ограничения тока, поэтому нам нужно добавить конфигурацию Redis и RequestRateLimiter, здесь все GET-запросы ограничены IP;
server:
  port: 9201
spring:
  redis:
    host: localhost
    password: 123456
    port: 6379
  cloud:
    gateway:
      routes:
        - id: requestratelimiter_route
          uri: http://localhost:8201
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 #每秒允许处理的请求数量
                redis-rate-limiter.burstCapacity: 2 #每秒最大处理的请求数量
                key-resolver: "#{@ipKeyResolver}" #限流策略,对应策略的Bean
          predicates:
            - Method=GET
logging:
  level:
    org.springframework.cloud.gateway: debug
  • Запросить адрес несколько раз:http://localhost:9201/user/1, будет возвращена ошибка с кодом состояния 429;

Retry GatewayFilter

Фильтр для повторной попытки запроса маршрутизации может определить, следует ли повторить попытку, в соответствии с кодом состояния HTTP, возвращенным запросом маршрутизации.

  • Измените файл конфигурации:
spring:
  cloud:
    gateway:
      routes:
      - id: retry_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - name: Retry
          args:
            retries: 1 #需要进行重试的次数
            statuses: BAD_GATEWAY #返回哪个状态码需要进行重试,返回状态码为5XX进行重试
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
  • Когда вызов вернет 500, он повторит попытку, посетите тестовый адрес:http://localhost:9201/user/111

  • Можно обнаружить, что консоль службы пользователя сообщает о двух ошибках, указывающих на повторную попытку.

2019-10-27 14:08:53.435 ERROR 2280 --- [nio-8201-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
	at com.macro.cloud.controller.UserController.getUser(UserController.java:34) ~[classes/:na]

Использовать вместе с реестром

мы говорили в прошлый разИспользование Zuul в качестве шлюзаПри использовании вместе с реестром Zuul по умолчанию создает динамический маршрут с именем службы path на основе списка служб, зарегистрированного в реестре.Шлюз также реализует эту функцию. Ниже мы покажем, как Gateway использует динамические маршруты и фильтры по умолчанию в сочетании с реестром.

Используйте динамическую маршрутизацию

  • Добавьте связанные зависимости в pom.xml:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • Добавьте файл конфигурации application-eureka.yml:
server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能
          lower-case-service-id: true #使用小写服务名,默认是大写
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug
  • Используйте файл конфигурации application-eureka.yml для запуска службы API-шлюза, доступа к http://localhost:9201/user-service/user/1 и маршрутизации к http://localhost:8201/user/1 пользователя. -сервис .

использовать фильтр

При использовании фильтров совместно с реестром нужно обратить внимание на то, что протокол urilb, чтобы можно было включить функцию балансировки нагрузки шлюза.

  • Измените файл application-eureka.yml и используйте фильтр PrefixPath, который будет добавлен ко всем путям GET-запросов./userпуть и маршрут;
server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: lb://user-service #此处需要使用lb协议
          predicates:
            - Method=GET
          filters:
            - PrefixPath=/user
      discovery:
        locator:
          enabled: true
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug
  • Используйте файл конфигурации application-eureka.yml для запуска службы API-шлюза, доступа к http://localhost:9201/1 и маршрутизации к http://localhost:8201/user/1 пользовательской службы.

используемые модули

springcloud-learning
├── eureka-server -- eureka注册中心
├── user-service -- 提供User对象CRUD接口的服务
└── api-gateway -- gateway作为网关的测试服务

Адрес исходного кода проекта

GitHub.com/macro-positive/…

публика

проект торгового центраПолный набор учебных пособий сериализуется,Обратите внимание на публичный аккаунтПолучите это прямо сейчас.

公众号图片