官网
我们要使用gateway的话,需要springboot是2.x的版本
什么是网关(gateway): Gateway是在spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot2和Project Reactor等技术。 Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等,他的主要功能还是“反射代理”和“过滤”
详情知识:
-
SpringCloud Gateway是SpringCloud的一个全新项目,基于Spring5.0+SpringBoot2.0和Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式。
-
为了提升网关的性能,SpringCloud Gatway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通讯框架Netty。 SpringCloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全、监控/指标、和限流。
能干嘛
-
反向代理
-
鉴权
-
流量控制
-
熔断
-
日志监控
三大核心概念:
-
Route(路由)
-
Predicate(断言)
-
Filter(过滤)
案例实现:
创建一个新的网关项目(cloud-gateway-gateway9527):
添加相应的依赖
<dependencies>
<!--新增gateway,不需要引入web和actuator模块-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
server:
port: 9527
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
添加启动类(已经写过很多次,注意,添加Eureka的客户机的注释)
9527的服务如何进行路由映射呢
就是我们访问8001端口的服务时,会暴露相应的端口号,但是我们如何将8001隐藏掉呢
添加相应的配置文件:
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
我们可以给routes下添加多个路径映射项,就很像vue中的router
每一项由id,uri,predicates这几个构成:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
启动相应的服务来进行测试(要先启动eureka服务)
我们可以看到他将/payment/get/31通过匹配上面久规则然后转发到了8001的服务上了
利用getway实现负载均衡:
我们将8002服务也启动,8001和8002所有的服务和功能都是相同的,他们就是用来实现负载均衡的
将gateway项目中的配置方中的8001请求的uri设置成服务名,:
网关就会通过服务名去匹配到8001,和8002的服务名,然后实现负载均衡
设置系统断言:
利用after来进行设置,后面添加一个时间,就是指在什么时间之后这个服务才可以被访问,否则将无法被访问到:
设置断言
查看当前时间利用如下函数,可以写一个测试类然后输出结果:
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
时间设置成23分钟的时候才可以被访问,现在访问情况如下
时间到了就可以访问了
Filter过滤器:
自定义过滤器(设置访问权限)
创建一个类,让他实现exchange,GatewayFilterChain这两个接口,并实现他们的方法:
给这个类添加一个注释,让这个类变成一个组件
在filter方法中编写相应的权限的做对:
package com.atguigu.springcloud.Filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*********come in MyLogGateWayFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("username");//获取用户名
if(StringUtils.isEmpty(uname) && uname.equals("admin")){
log.info("*****用户名为Null 非法用户,(┬_┬)");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}