Введение в Spring Cloud Gateway
Не много ерунды, посмотрите введение в официальную документацию
This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.
Есть способ перевести:
Этот проект предоставляет шлюз API, построенный на основе экосистемы Spring, включая: Spring 5, Spring Boot 2 и проект Reactor. Spring Cloud Gateway стремится предоставить простой и эффективный способ маршрутизации к API и предоставить им сквозные проблемы, такие как: безопасность, мониторинг/метрики и отказоустойчивость.
Это работает следующим образом:
Шлюз фактически обеспечивает функцию управления маршрутизацией, которая обычно включает две основные функции:
- Route
- Filter
- Forward
Мы можем сопоставить запрошенный uri через Route, и цепочка фильтров может быть настроена для каждого маршрутизатора.Мы можем использовать Filter для изменения запросов и ответов и некоторых промежуточных действий, таких как аутентификация, а Forward может управлять перенаправлением и переадресацией запросов (на самом деле он также может сделать на фильтре, но здесь это немного понятнее). В управлении маршрутизацией Gateway очень гибок, имеет два метода настройки:
- Yml or Properties File
- Code
Основные существительные следующие:
- Route: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.
- Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This allows developers to match on anything from the HTTP request, such as headers or parameters.
- Filter: These are instances Spring Framework GatewayFilter constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.
Как основной элемент в шлюзе, маршрут имеет свой собственный идентификатор, URI, а также коллекцию предикатов и коллекцию фильтров. Функция Predicate состоит в том, чтобы определить, соответствует ли запрошенный Uri текущему маршруту, а фильтр — обработать и изменить запрос и ответ после того, как совпадение будет передано.Тогда основная структура маршрута в шлюзе выглядит следующим образом.
Gateway{
Route1 {
String id;
String path;
List<Predicate> predicates;
List<Filter> filters;
};
Route2 {
String id;
String path;
List<Predicate> predicates;
List<Filter> filters;
};
...
...
}
Идентификатор в Маршруте является его уникальным идентификатором. Роль пути заключается в том, чтобы регулярно сопоставлять путь запроса, а Предикат — в дальнейшем более подробном сопоставлении пути запроса, когда путь совпадает, как показано в следующем примере:
spring:
cloud:
gateway:
routes:
- id: before_route
uri: http://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
СоответствуетJan 20, 2017 17:42
инициированный запрос
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://example.org
predicates:
- Cookie=chocolate, “”
Только совпадения, переданные в запросеchocolate
и значениеch.p
запрос
Больше примеров здесь раскрывать не буду, если вам интересно, вы можете перейти к официальной документации:портал
Конфигурация Spring Cloud Gateway
Maven
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway</artifactId>
<version>2.0.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Yml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://example.org
predicates:
- Cookie=chocolate, ch.p
Java Config
@Configuration
@RestController
@SpringBootApplication
public class Application {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/request/**")
.and()
.predicate(new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange t) {
boolean access = t.getRequest().getCookies().get("_9755xjdesxxd_").get(0).getValue().equals("32");
return access;
}
})
.filters(f -> f.stripPrefix(2)
.filter(new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange);
}
}, 2)
.filter(new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange);
}
}, 1))
.uri("http://localhost:8080/hello")
).build();
}
@GetMapping("/hello")
public String hello() {
return "hello";
}
public static void main(String[] args) throws ClassNotFoundException {
SpringApplication.run(Application.class, args);
}
}
Конфигурация Yml и конфигурация кода Java могут сосуществовать.Преимущество конфигурации Yml заключается в том, что вы можете напрямую использовать некоторые предикаты и фильтры, в то время как конфигурация кода Java более гибкая!
Использование Spring Cloud Gateway
Как упоминалось выше, Gateway поддерживает две конфигурации.В этой статье основное внимание уделяется Java Config, так как объяснение конфигурации Yml в официальной документации достаточно глубоко.Если вам интересно, вы можете ввестипортал
Route
Конфигурация маршрута может быть достаточно простой
@Configuration
@RestController
@SpringBootApplication
public class Application1 {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/user/**")
.uri("http://localhost:8080/hello")
).build();
}
@GetMapping("/hello")
public String hello() {
return "hello";
}
public static void main(String[] args) throws ClassNotFoundException {
SpringApplication.run(Application1.class, args);
}
}
Вышеприведенная демонстрация определяет маршрут, а значение пути равно/**
, что означает соответствие нескольким уровням uri, если путь изменен на/*
Это означает, что может быть сопоставлен только один слой. Итак, запустите указанную выше программу, после чего все запросы будут перенаправлены наhttp://localhost:8080/hello
Если в конфигурации uri нет определенного ресурса, напримерhttp://ip:port
,Так/**
Совпадающий путь будет автоматически собран после uri:
request http://当前服务/user/1
forward http://ip:port/user/1
Этот способ больше подходит для переадресации между сервисами, мы можем установить uri какip:port
также можно установитьxxx.com
доменное имя, но не может перенаправлять свои собственные службы, такие как
request http://当前服务/user/1
forward http://当前服务/user/1
Это приводит к ошибке HTTP 413, которая бесконечно переадресовывается на себя, а это означает, что запрос заблокирован, что очень фатально! Лучший способ следующий:
Мы планируем открыть порты, занятые двумя сервисами:8080
и8081
, если мы хотим8080
обслуживание через/user/**
Сопоставление маршрута вперед к8081
сервис, вы можете сделать это:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("hello", r -> r
.path("/user/**")
.and()
.uri("http://localhost:8081")
).build();
}
Отслеживание работы:
request http://localhost:8080/user/hello
forward http://localhost:8081/user/hello
Определение интерфейса службы 8081:
@GetMapping("/user/hello")
public String hello() {
return "User Say Hello";
}
Текст ответа:
User Say Hello
Когда Gateway заменит Zuul, то есть после того, как связь между сервисами будет преобразована из Zuul в Gateway, написание uri будет выглядеть так:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("user/**")
.uri("lb://USER_SERVER_NAME")
).build();
}
Приведенный выше код будетuser/**
Соответствие запросу переадресовано всемUSER_SERVER_NAME
Под сервисом:
request /user/1
forward http://USER_SERVER_HOST:USER_SERVER_PORT/user/1
вlbна самом деле означаетload balance
Это означает, что я думаю, что разработчики используют lb для различения режима маршрутизации.Возможно, балансировка нагрузки означает мультисервисную среду, поэтому lb может указывать на то, что объект пересылки изменился с указанного uri на службу!
Predicate
Predicate — новая библиотека в Java 8+, предназначенная для выполнения логических операций, поддерживаемые типы:
- isEqual
- and
- negate
- или
Есть другой способ
test(T)
Используется для запуска логических вычислений для возврата значения логического типа.
Шлюз использует Predicate для вынесения суждений о сопоставлении, отличных от сопоставления с шаблоном пути, который очень прост в использовании:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("hello", r -> r
.path("/user/**")
.and()
.predicate(e -> e.getClass() != null)
.uri("http://localhost:8081")
).build();
}
Входeпредставляет собойServerWebExchange
объект, мы можем пройтиServerWebExchange
Получите всю информацию, связанную с запросом, такую как файлы cookie и заголовки. Используйте синтаксис Lambda для написания логики суждения.Если все результаты, возвращаемые предикатом в маршруте, равны ИСТИНА, сопоставление завершается успешно, в противном случае сопоставление завершается ошибкой.
Tp: путь и предикат нужно использовать и связывать, или использовать или связывать для представления различных логических операций!
Filter
Роль фильтра аналогична роли предиката, разница в том, что предикат может сделать запрос прерывания, фильтр может сделать это, фильтр может сделать модификацию ответа, а предикат не может этого сделать, то есть фильтр является последним перехватом , и есть много вещей, которые можно сделать. Например, изменить ответное сообщение, добавить заголовок или файл cookie или даже изменить тело ответа. Напротив, фильтр более универсален!
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("hello", r -> r
.path("/user/**")
.and()
.predicate(e -> e.getClass() != null)
.filters(fn -> fn.addResponseHeader("developer", "Nico"))
.uri("http://localhost:8081")
).build();
}
Как работает Spring Cloud Gateway
Gateway — это контроллер маршрутизации шлюза, основанный на Spring MVC, мы можем напрямую найти Spring MVC.org.springframework.web.reactive.DispatcherHandler
класс, егоhandle
Метод будет обработан после разбора запросаServerWebExchange
объект.
Входитьhandle
метод, который будет проходить с помощью Fluxorg.springframework.web.reactive.DispatcherHandler.handlerMappings
правильноServerWebExchange
обрабатывать,handlerMappings
Содержит следующие процессоры:
org.springframework.web.reactive.function.server.support.RouterFunctionMapping@247a29b6, org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping@f6449f4, org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping@535c6b8b,
org.springframework.web.reactive.handler.SimpleUrlHandlerMapping@5633e9e
Выше приведен простой обработчик запросов Flux.concatMap
метод объединит Mono каждого процессора в Flux, а затем вызоветorg.springframework.web.reactive.DispatcherHandler
в классеinvokeHandler
метод начинает обработкуServerWebExchange
, возвращаемое значение будет обработано сразу после обработки, затем используйтеhandleResult
метод, конкретная реализация выглядит следующим образом:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
ServerHttpRequest request = exchange.getRequest();
logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
}
if (this.handlerMappings == null) {
return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
Ключом к функционированию Gateway является то, чтоinvokeHandler
В методе:
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
После того, как адаптер соответствующего процессора совпадет сам с собой, будет запущен метод обработки адаптера.Каждый процессор будет реализовывать соответствующий интерфейс, и они, как правило, имеют общую особенность:
public interface Handler {
Mono<Void> handle(ServerWebExchange exchange);
}
Метод обработчика каждого адаптера вызывает обработчик обработчика после вставки логического кода адаптера.handle
метод, все обработчики Spring Cloud Gateway находятся вorg.springframework.cloud.gateway.handler
Под пакетом:
org.springframework.cloud.gateway.handler.AsyncPredicate<T>
org.springframework.cloud.gateway.handler.FilteringWebHandler
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
Видно, что вышеупомянутые три процессора имеют дело с Filter и Predicate соответственно.Заинтересованные друзья могут взглянуть на конкретную реализацию внутри этих классов, и я не буду здесь вдаваться в подробности.
В общем, принцип Spring Cloud Gateway заключается в считывании собственной конфигурации во время загрузки службы и сохранении информации в контейнере, а также извлечении информации, когда Spring Mvc обрабатывает запрос.логическое суждениеифильтр, запускать разные события в зависимости от результатов обработки!
И студенты, которые заинтересованы в том, чтобы запросить пересылку этого материала, могут пойти и изучить его!
ТП: Сопоставление пути на самом деле является логическим суждением предикатов.
Резюме Spring Cloud Gateway
Автор случайно увидел ответ под вопросом spring-cloud-netflixпортал:
Lovnx:Zuul 2.0 has opened sourcing,Do you intend to integrate it in some next version?
spencergibb:No. We created spring cloud gateway instead.
Только тогда я почувствовал, что Spring Cloud действительно доминирует, и поэтому я вступил в контакт со Spring Cloud Gateway, и я почувствовал, что необходимо его изучить.Вообще говоря, Spring Cloud Gateway упрощает сложность предыдущей настройки фильтра, а также увеличивает новый метод конфигурации.Конфигурация шлюза микросервисов может напрямую заменить Zuul, с нетерпением ожидая собственного реестра Spring.
Автор плохо учится, и приведенные выше объяснения неверны.Надеюсь покритиковать и указать.Контакт: ainililia@163.com
Документация
официальная документация Начало работы с Spring Cloud Gateway Концепция Reactor Flux и Mono в реактивном программировании