Gateway网关
一、Gateway概念
Cloud全家桶有个狠重要的组件就是网关,在1.x版本中都是采用Zuul网关;但是在2.x版本中,zuul的升级一致跳票,SpringCloud最后自己研发了一个网关替代Zuul, 那就是SpringCloud Gateway
二、三大核心概念
1.Route (路由)
路由是构建网关的基本模块,它由ID,目标URL,一系列的断言和过滤器组成,如果断言为true则匹配该路由
2.Predicate (断言)
参考的是Java8的java.util.function.predicate
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
3.Filter (过滤)
指的是Spring框架中的GatewayFilter 的实例,使用过滤器,可以在请求被路由前或者之后请求进行修改
三、工作流程图
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
四、工程搭建
1、新建Gateway网关工程
2、添加项目需要使用的依赖包
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--consul-server服务注册发现-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
</dependencies>
3、application.yml配置
server:
port: 8080
spring:
application:
name: cloud-gateway
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name} # 注册到consul的服务名称
gateway:
routes:
- id: payment_routh #路由ID,没有固定的规则单要求唯一,最好和服务名称配置一致
uri: http://localhost:9001 #匹配后提供路由的服务地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行断言
- id: payment_routh #======================可以匹配多个=======================
uri: http://localhost:9001 #匹配后提供路由的服务地址
predicates:
- Path=/payment/consul/** #断言,路径相匹配的进行断言
4、启动器
/**
* @description: 网关启动器
* @author: ydf
* @date: 2021/1/3 16:08
* @version: v1.0
*/
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class GatewayAppMain {
public static void main(String[] args) {
SpringApplication.run(GatewayAppMain.class,args);
}
}
5、测试
6、转发功能同样可以通过代码来实现
/**
* @description: Gateway配置
* @author: ydf
* @date: 2021/1/3 16:30
* @version: v1.0
*/
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/guonei").uri("http://news.baidu.com"))
.build();
}
}
上面配置了一个 id 为 path_route 的路由,当访问地址http://localhost:8080/guonei时会自动转发到地址:http://news.baidu.com/guonei和上面的转发效果一样,只是这里转发的是以项目地址/guonei格式的请求地址。
7、开启动态创建路由
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh1
#uri: http://localhost:9001
uri: lb://provider-service #匹配后提供的路由地址(微服务名进行路由)
predicates:
- Path=/payment/get/**
- id: payment_routh2
#uri: http://localhost:9002
uri: lb://provider-service #匹配后提供的路由地址(微服务名进行路由)
predicates:
- Path=/payment/consul/**
测试:
五、Gateway常用Predicate
Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来我们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。
官方配置:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gateway-request-predicates-factories
这里的配置有十多种,官方说的很明确,改一下配置文件就行了,这里小编就不演示了。
六、Gateway的Filter
全局过滤器配置:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#global-filters
配置类:
/**
* @description: 全局配置Gateway的过滤器
* @author: ydf
* @date: 2021/1/3 19:35
* @version: v1.0
*/
@Component
public class CustomGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("GlobalFilter***************************"+new Date());
//模拟演示拦截---实际生产当中可以拦截验证头部是否携带token等
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname == null){
System.out.println("uname为null,非法用户");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
测试:
携带正确的参数,再次请求测试:
http://localhost:8080/payment/consul?uname=dtydf
总结
小总结: 实际项目中网关微服务一般都用来作为整个服务入口的鉴权操作,假设我们再对JWT的加解密过程中使用的对称加密算法,这样就会不可避免的导致一个安全隐患:如果有恶意请求利用密钥生成了JWT令牌来进行登录操作,那就会产生不可预知的后果!
解决方式:
采用非对称算法,生成一个存储着公钥和私钥的密钥库,在生成JWT的时候,使用私钥来进行加密,而解析JWT的服务使用公钥来解析JWT,这样将加密和解析的两把密钥分开来,就可以阻止恶意用户对系统产生恶意攻击了。