概述
spring cloud gateway提供了一个构建在 Spring 生态系统之上的 API 网关,包括:Spring 5、Spring Boot 2 和 Project Reactor。 Spring Cloud Gateway 旨在提供一种简单而有效的方式来路由到 API 并为它们提供交叉关注点,例如:安全性、监控/指标和弹性。
- 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 the aggregate predicate is true.
-
Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework
ServerWebExchange
. This lets you match on anything from the HTTP request, such as headers or parameters. -
Filter: These are instances of
GatewayFilter
that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.
依赖的框架以及版本
工具 | 版本 |
---|---|
spring-boot | 2.5.0 |
spring-cloud | 2020.0.1 |
Spring Cloud Alibaba | 2021.1 |
nacos | 2.0.3 |
实现步骤
1,spring cloud gateway与nacos集成两步~
-
添加依赖
<properties> <java.version>1.8</java.version> <spring-cloud.version>2020.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
-
配置application.yml文件,无需配置到bootstrap.yml文件中了,新版本nacos配置会报错。
spring: application: name: gateway cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true # routes: # - id: header_route # uri: lb://archetype # predicates: # - Header=X-Request-Id, \d+ nacos: discovery: server-addr: 127.0.0.1:8848 namespace: lqd password: nacos username: nacos
-
Postman验证:
image-20210817094935112.png
2,了解下Route、Predicates、Filter
-
Route、Predicates 验证:Route Predicate Factories The Header Route Predicate Factory 请求头过滤添加如下配置,通过Postman请求验证
image-20210817095807823.png image-20210817095846592.pngroutes: - id: header_route uri: lb://archetype predicates: - Header=X-Request-Id, \d+
-
Filter验证The
AddResponseHeader
GatewayFilter
Factory
image-20210817103422397.pngroutes: - id: header_route uri: lb://archetype predicates: - Header=X-Request-Id, \d+ filters: - AddResponseHeader=X-Response-TIME, 20210817
关键源码
Predicate的核心类RoutePredicateHandlerMapping、AbstractRoutePredicateFactory
-
RoutePredicateHandlerMapping
protected Mono<Route> lookupRoute(ServerWebExchange exchange) { return this.routeLocator.getRoutes() // individually filter routes so that filterWhen error delaying is not a // problem .concatMap(route -> Mono.just(route).filterWhen(r -> { // add the current route we are testing exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId()); return r.getPredicate().apply(exchange); }) // instead of immediately stopping main flux due to error, log and // swallow it .doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e)) .onErrorResume(e -> Mono.empty())) // .defaultIfEmpty() put a static Route not found // or .switchIfEmpty() // .switchIfEmpty(Mono.<Route>empty().log("noroute")) .next() // TODO: error handling .map(route -> { if (logger.isDebugEnabled()) { logger.debug("Route matched: " + route.getId()); } validateRoute(route, exchange); return route; }); /* * TODO: trace logging if (logger.isTraceEnabled()) { * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); } */ }
Filter核心类DefaultGatewayFilterChain、核心接口GlobalFilter、代理请求转发类NettyRoutingFilter
- DefaultGatewayFilterChain这个类可以看到springCloud的Filter的责任链。
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
例如:RouteToRequestUrlFilter通过这个类可以方便查看到路由后的访问路径。
-
NettyRoutingFilter这个类是gateway转发服务到代理服务的处理类
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); String scheme = requestUrl.getScheme(); if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) { return chain.filter(exchange); } setAlreadyRouted(exchange); ServerHttpRequest request = exchange.getRequest(); final HttpMethod method = HttpMethod.valueOf(request.getMethodValue()); final String url = requestUrl.toASCIIString(); HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange); final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders(); filtered.forEach(httpHeaders::set); boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false); Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange).headers(headers -> { headers.add(httpHeaders); // Will either be set below, or later by Netty headers.remove(HttpHeaders.HOST); if (preserveHost) { String host = request.getHeaders().getFirst(HttpHeaders.HOST); headers.add(HttpHeaders.HOST, host); } }).request(method).uri(url).send((req, nettyOutbound) -> { if (log.isTraceEnabled()) { nettyOutbound.withConnection(connection -> log.trace("outbound route: " + connection.channel().id().asShortText() + ", inbound: " + exchange.getLogPrefix())); } return nettyOutbound.send(request.getBody().map(this::getByteBuf)); }).responseConnection((res, connection) -> { ...... return responseFlux.then(chain.filter(exchange)); }
异常报错
1,出现503 Service Unavailable
解决方法:增加spring-cloud-starter-loadbalancer依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
参考
spring cloud 与 spring cloud alibaba 版本对应关系
spring cloud gateway
Reactor 3
Spring 5 WebFlux
例子
网友评论