Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
1.为什么需要网关?
Gateway网关是我们服务的守门神,所有微服务的统一入口。
网关的核心功能特性:
-
请求路由
-
权限控制
-
限流
架构图:
权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。
路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。
在SpringCloud中网关的实现包括两种:
-
gateway
-
zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
2.快速入门
(1)引入相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)yml配置文件
server:
port: 81
spring:
application:
name: gateway #网关服务名称
#gateway路径规则
cloud:
gateway:
routes:
#微服务1
- id: product-service #商品服务的路由标志
uri: lb://product-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/product/**
#微服务2
- id: order-service #订单服务的路由标志
uri: lb://order-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/order/**
#将网关服务注册到 nacos
nacos:
discovery:
server-addr: localhost:8848
register-enabled: false #只负责拉取服务,不注册
(3)访问81端口
(4)gateway自动定位功能
修改配置文件为
server:
port: 81
spring:
application:
name: gateway #网关服务名称
#使用 gateway开启微服务的自定定位
cloud:
gateway:
discovery:
locator:
enabled: true #默认是false
#将网关服务注册到 nacos
nacos:
discovery:
server-addr: localhost:8848
register-enabled: false #只负责拉取服务,不注册
访问时路径上 加上微服务名即可
3.断言工厂
yml文件配置示例:
spring:
application:
name: gateway #网关服务名称
#gateway路径规则
cloud:
routes:
#微服务1
- id: product-service #商品服务的路由标志
uri: lb://product-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/product/**
#微服务2
- id: order-service #订单服务的路由标志
uri: lb://order-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/order/**
其他的一些断言工厂:
4.过滤器工厂
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
4.1.路由过滤器的种类
Spring提供了31种不同的路由过滤器工厂。例如:
4.2.全局过滤器
全局过滤器的作用也是处理一切进入网关的请求和微服务响应。
主要用于:
- 认证判断
- 权限校验
- 黑白名单
- 跨域配置
- 请求限流
认证判断
当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
以后每次请求,客户端都携带认证的token
服务端对token进行解密,判断是否有效。
4.2.1自定义全局过滤器
@Component
public class LoginFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获取请求路径
String path = String.valueOf(request.getPath());
//符合就放行
if("/login".equals(path)){
return chain.filter(exchange);
}
//获取请求头token
String token = request.getHeaders().getFirst("token");
//判断是否携带token
if(StringUtils.hasText(token) && "admin".equals(token)){
//必须携带token并且是admin才能访问资源
return chain.filter(exchange);
}
//json数据
Map<String, Object> map = new HashMap<>();
map.put("msg", "未登录");
map.put("code", 403);
//3.3作JSON转换
byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8);
//3.4调用bufferFactory方法,生成DataBuffer对象
DataBuffer buffer = response.bufferFactory().wrap(bytes);
//4.调用Mono中的just方法,返回要写给前端的JSON数据
return response.writeWith(Mono.just(buffer));
}
//过滤器优先级,越小越高
@Override
public int getOrder() {
return 0;
}
}
-
每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
-
GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
-
路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
-
当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
5.解决跨域问题(两种)
(1)自定义跨域的配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* 解决跨域配置类
*/
@Configuration
public class CorsConfig {
//处理跨域
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
(2)yml配置文件(推荐)
spring:
cloud:
gateway:
#跨域问题解决配置
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]': #拦截的请求
allowedOrigins: #允许跨域的请求
- "http://localhost:81"
allowedMethods: #运行跨域的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许请求中携带的头信息
allowCredentials: true #是否允许携带cookie
maxAge: 36000 #跨域检测的有效期,单位s
6.nginx反向代理gateway集群
6.1配置文件
(1)nginx.conf配置
server {
listen 82;
server_name localhost;
location /{
#反向代理的服务器ip和端口号
proxy_pass http://wjq;
}
}
# 负载均衡配置 集群服务器的ip和端口 weight=2 设置权重策略
upstream wjq{
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 weight=1;
}
(2)gateway实例yml配置
实例A
server:
port: 8081
spring:
application:
name: gateway-A #网关服务名称
#gateway路径规则
cloud:
gateway:
#跨域问题解决配置
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]': #拦截的请求
allowedOrigins: #允许跨域的请求
- "http://localhost:81"
allowedMethods: #运行跨域的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许请求中携带的头信息
allowCredentials: true #是否允许携带cookie
maxAge: 36000 #跨域检测的有效期,单位s
routes:
#微服务1
- id: product-service #商品服务的路由标志
uri: lb://product-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/product/**
#微服务2
- id: order-service #订单服务的路由标志
uri: lb://order-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/order/**
#将网关服务注册到 nacos
nacos:
discovery:
server-addr: localhost:8848
register-enabled: true #只负责拉取服务,不注册
实例B
server:
port: 8082
spring:
application:
name: gateway-B #网关服务名称
#gateway路径规则
cloud:
gateway:
#跨域问题解决配置
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]': #拦截的请求
allowedOrigins: #允许跨域的请求
- "http://localhost:81"
allowedMethods: #运行跨域的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许请求中携带的头信息
allowCredentials: true #是否允许携带cookie
maxAge: 36000 #跨域检测的有效期,单位s
routes:
#微服务1
- id: product-service #商品服务的路由标志
uri: lb://product-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/product/**
#微服务2
- id: order-service #订单服务的路由标志
uri: lb://order-service #转发的地址
#断言:当满足断言的条件,才会真正转发到uri地址
predicates:
- Path=/order/**
#将网关服务注册到 nacos
nacos:
discovery:
server-addr: localhost:8848
register-enabled: true #只负责拉取服务,不注册
注意:一定要将两个实例都注册到nacos中,不然无法实现nginx的负载均衡
6.2.模拟gateway集群
(1)选中gateway服务右击:
(2)选择copy配置
(3)点击Modify options
(4)点击add VM
(5)设置端口为8083
(6)应用和确认即可
(7)最后分别启动gateway服务即可