一、介绍
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
二、为什么要使用网关
在微服务架构中,每个微服务都有各自的容器或服务器,都有不同的IP,那么前端程序在访问后端程序的时候,需要根据不同的微服务配置不同的Ajax请求地址,这样无疑加大了前端开发人员的工作量;其次在常规的程序中,基本都涉及到登录验证以及鉴定权限的功能,那么基于微服务架构,是不是每个微服务都需要验证请求是否合法或者是否具备权限,这样也同样加大了后端开发人员的工作量。
网关很好的解决了这些问题,网关如何解决?
网关的核心功能:请求路由、权限控制、限流
权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。
路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。
架构图:
三、快速搭建一个网关服务
1、创建一个GateWay服务
2、引入网关的依赖
网关需要转发请求,所以也需要导入注册中心
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
至此,网关服务其实已经搭建完成,核心点在于网关的配置‘
3、编写基础配置和路由规则:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
路由配置包括:
- 路由id:路由的唯一标示
- 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
- 路由断言(predicates):判断路由的规则,
- 路由过滤器(filters):对请求或响应做处理
4、此时即可进行网关服务的启动,并测试
5、网关路由的流程图
四、断言工厂
gateway里面的断言条件是predicates属性,它的作用就是过滤访问条件,满足它设置的条件才放行例如上述例子的配置文件中的,满足 - PATH = /USER/**:这个就是满足访问路径为/user开头的才放行;
常规来说实际应用中Path使用的比较多,其他的比较少
以下列举一系列断言:
名称 | 说明 | 示例 |
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
五、过滤器
· 网关的过滤器与常规的过滤器功能类似,都是拦截请求,并对当前请求进行一系列的操作,例如登录验证、权限鉴定等;网关提供了过滤器工厂,可以通过配置的方式快速的完成过滤器的配置,以下列举部分:
名称 | 说明 |
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
配置方式:
路由过滤器:
直接在网关的配置中添加filters+实际的过滤条件即可,如下所示,就是在当前的routes中添加一个AddRequestHeader过滤器,并在每个请求头中添加一个Truth属性,属性值为TestFilter
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, TestFilter! # 添加请求头
默认过滤器:
上述配置可以看到,filters是配置在routes中的,只对当前配置的routes有效,在实际应用中网关会配置很多条routes,如果存在相同的过滤器配置,那每条routes都需要相同的过滤器配置,这样很麻烦,于是就有了default-filters配置:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, TestFilter!
default-filters的配置作用跟filters相同,只是default-filters是对所有路由生效,只需要配置一次
全局过滤器:
这是比default-filters作用范围更广的过滤器,上述的两种过滤器都是可以进行配置的,全局过滤器需要开发人员自己写代码实现过滤规则,需要实现核心接口GlobalFilter:如下实现是否为admin的判断
@Componentpublic
class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求头中的auth属性
String auth = exchange.getRequest().getQueryParams().getFirst("auth");
//判断是否为管理员
if ("admin".equals(auth)){
//放行
return chain.filter(exchange);
}
//不具备admin权限拦截
//设置返回的状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//结束请求,并返回
return exchange.getResponse().setComplete();
}
PS:过滤器实现的顺序:
当然也可以通过@Order注解进行手动排序,此处不做说明
六、跨域问题处理
跨域:域名不一致就是跨域,主要包括:
- 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
- 域名相同,端口不同:localhost:8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
网关提供了解决跨域的配置
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期