Подробное описание Spring Cloud Gateway

Spring Cloud

Введение в 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 и предоставить им сквозные проблемы, такие как: безопасность, мониторинг/метрики и отказоустойчивость.

Это работает следующим образом:

image

Шлюз фактически обеспечивает функцию управления маршрутизацией, которая обычно включает две основные функции:

  • 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 в реактивном программировании