更多Spring与微服务相关的教程请戳这里 Spring与微服务教程合集
1、核心概念
1.1、路由route
路由是网关最基础的部分。路由信息由一个ID、一个目的url、一组断言工厂和一组Filter组成。如果路由断言为真,则说明请求的url和配置的路由匹配。
1.2、断言predicate
Java8中的断言函数。spring cloud gateway中的断言函数输入类型是spring5.0框架中的ServerWebExchange。spring cloud gateway中的断言函数允许开发者去定义来自于Http Request中的任何信息,比如请求头和参数等。
1.3、过滤器filter
一个标准的spring webfilter。spring cloud gateway中的filter分为两种类型:分别是gateway filter和global filter。
2、工作原理

- gateway客户端向gateway发起请求
- 请求首先被HttpWebHandlerAdapter进行提取组装成网关的上下文
- 然后网关上下文会传递到DispatcherHandler
- DispatcherHandler是所有请求的分发处理器,主要负责分发请求对应的处理器。比如将请求分发到对应的RoutePredicate-HandlerMapping(路由断言处理映射器)
- 路由断言处理映射器主要用于路由的查找,以及找到路由后返回对应的FilterWebHandler
- FilterWebHandler主要负责组装Filter链表并调用Filter执行一系列的Filter处理,然后把请求转到后端对应的代理服务处理
- 处理完毕后,将response返回给gateway客户端
注意:
- 过滤器分为Pre和Post,分别在转发请求之前处理和接收到代理服务返回的结果之后处理
- 在配置路由时,如果不指定端口,则http默认端口为80,https默认端口为443
- gateway目前只支持netty容器
2、路由断言和过滤
2.1、概述
路由断言:
- Path路由断言工厂
- Before路由断言工厂
- Between断言工厂
- Cookie路由断言工厂
- Header路由断言工厂
- Host路由断言工厂
- Method路由断言工厂
- Query路由断言工厂
- RemoteAddr路由断言工厂
路由过滤:
spring cloud gateway内置了很多的路由过滤工厂,也可以根据需要自定义路由过滤工厂
路由过滤器允许以某种方式修改request或response
2.2、基于yml配置
spring:
cloud:
gateway:
routes:
- id: findAll
uri: http://localhost:8130
predicates:
- Path=/findAll
- id: findOne
uri: http://localhost:8130
predicates:
- Path=/findOne
2.3、基于JavaConfig配置
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
import org.springframework.cloud.gateway.route.builder.PredicateSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.UriSpec;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.function.Function;
@Configuration
public class GatewayRouteConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
ZonedDateTime dateTime = ZonedDateTime.of(2020, 10, 17, 22, 40, 0, 0, ZoneId.systemDefault());
return builder.routes()
//普通path断言
.route(r->r.path("/getStudentName")
.filters(new Function<GatewayFilterSpec, UriSpec>() {
@Override
public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
return gatewayFilterSpec.addRequestHeader("stuName", "bobo");
}
})
.uri("http://localhost:8130")
.id("getStudentName"))
//after断言+path断言
.route(new Function<PredicateSpec, Route.AsyncBuilder>() {
@Override
public Route.AsyncBuilder apply(PredicateSpec predicateSpec) {
predicateSpec.path("/listStudent").and().after(dateTime);
Route.AsyncBuilder asyncBuilder = predicateSpec.uri("http://localhost:8130");
asyncBuilder.id("listStudent");
return asyncBuilder;
}
})
//path通配符断言
.route(r->r.path("/student/**")
.uri("http://localhost:8130")
.id("student"))
.build();
}
}
3、gateway集成eureka服务注册中心
3.1、pom.xml
注意springboot和springcloud的版本,如果是其它版本,启动项目的时候可能会报错
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</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>
</dependencies>
</dependencyManagement>
3.2、application.yml关键配置
spring:
cloud:
gateway:
discovery:
locator:
#与服务注册中心集成
enabled: true
#因为eureka的serviceId默认是大写,设为true之后,在gateway中可以用小写的serviceId进行路由转发
lowerCaseServiceId: true
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka/
register-with-eureka: true
3.3、自动路由匹配
gateway与eureka集成后,即使不配置路由,也会进行自动路由匹配
比如在eureka上注册了一个服务提供者service-a,service-a的上下文是/service-a,端口是8080,且暴露了一个接口,路径为/student/getName
gateway的端口是9000,则访问http://localhost:9000/service-a/service-a/student/getName,可自动匹配到service-a
通过gateway的日志可以看到,自动路由的信息如下:
Route{id='ReactiveCompositeDiscoveryClient_SERVICE-A', uri=lb://SERVICE-A, order=0, predicate=Paths: [/service-a/**], \
其中,lb表示该uri从注册中心查找
4、Filter
4.1、概述
spring cloud gateway的Filter实际上分两种:
- GatewayFilter:应用到单个路由或一组路由,前面讲的路由过滤器工厂就是GatewayFilter
- GlobalFilter:应用到所有的路由
4.2、自定义GatewayFilter
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PrintHeaderGatewayFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("执行PrintHeaderFilter");
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
Set<Map.Entry<String, List<String>>> entries = headers.entrySet();
for (Map.Entry<String, List<String>> entry : entries) {
System.out.println(entry.getKey()+"----"+entry.getValue());
}
return chain.filter(exchange);
}
}
4.3、自定义GlobalFilter
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class TokenGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, String> queryParams =
exchange.getRequest().getQueryParams();
List<String> list = queryParams.get("token");
if(CollectionUtils.isEmpty(list)){
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
4.4、自定义GatewayFilterFactory
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class PrintParamGatewayFilterFactory extends AbstractGatewayFilterFactory<PrintParamGatewayFilterFactory.Config>{
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getURI().getPath();
if (!config.getIgnoreUrl().contains(url)){
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
for (String s : queryParams.keySet()) {
System.out.println(s+"----"+queryParams.get(s));
}
}
return chain.filter(exchange);
}
};
}
public PrintParamGatewayFilterFactory(){
super(Config.class);
}
/**
* 自定义config类,能读取到yml中的配置
*/
public static class Config{
private List<String> ignoreUrl;
public List<String> getIgnoreUrl() {
return ignoreUrl;
}
public void setIgnoreUrl(List<String> ignoreUrl) {
this.ignoreUrl = ignoreUrl;
}
}
}
spring:
cloud:
gateway:
routes:
- id: methodGet
order: -100
uri: http://localhost:8130
predicates:
- Method=GET
filters:
- name: PrintParam # 如果类名为 ???GatewayFilterFactory,则过滤器名为???
args:
ignoreUrl:
- /findAll
- /findOne
本文深入介绍了Spring Cloud Gateway的核心概念,包括路由、断言和过滤器的工作原理。详细讲解了如何配置路由断言如Path、Header等,并通过YAML和JavaConfig展示了配置示例。同时,文章还涵盖了Gateway如何与Eureka服务注册中心集成,实现自动路由匹配。此外,还探讨了自定义GatewayFilter和GlobalFilter的方法,以及如何创建自定义的GatewayFilterFactory。最后,给出了实际的代码示例来展示过滤器的使用。
2610

被折叠的 条评论
为什么被折叠?



