Gateway服务网关
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
1为什么需要网关
Gateway网关是我们服务的守门神,所有微服务的统一入口
网关的核心功能:
- 请求路由
- 权限控制
- 限流
架构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1poxBKB-1693053166324)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230825203446233.png)]
权限控制:网关作为微服务入口,需要校验用户是否有请求资格,如果没有则进行拦截
路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由,当然路由的目标服务器有多个时,还需要做负载均衡
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大
在SpringCloud中网关的实现包括两种:
- gateway
- zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
2gateway快速入门
下面,我们就演示下网关的基本路由功能。基本步骤如下:
- 创建SpringBoot工程gateway,引入网关依赖
- 编写启动类
- 编写基础配置和路由规则
- 启动网关服务进行测试
2.1创建gateway服务,引入依赖
<!--网关依赖-->
<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>
2.2编写启动类
@SpringBootApplication
public class GateApplication {
public static void main(String[] args) {
SpringApplication.run(GateApplication.class, args);
}
}
2.3编写基础配置和路由规则
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 #nacos地址
gateway:
routes:
- id: user-service #路由标识,必须唯一
uri: lb://userservice
predicates: #判断请求是否符合规则
- Path=/user/** #路径断言,判断路径是否以/user开头,如果是则符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
2.4启动
访问localhost:10010/user/1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zugYf5MW-1693053166327)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826190836701.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMju0ty5-1693053166328)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826190932259.png)]
总结:
1.创建项目,引入nacos服务发现和gateway依赖
2.配置application.yml,包括服务基本信息,nacos地址,路由
路由配置包括:
1.路由id:路由的唯一标识
2.路由目标uri:路由的目标路径,http代表固定地址,lb代表根据服务名负载均衡
3.路由断言predicates:判断路由的规则
4.路由过滤器filters:对请求或响应做处理
3路由断言工厂Route Predicate Factory
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来
处理的,像这样的断言工厂在SpringCloudGateway还有十几个:
名称 | 说明 | 示例 |
---|---|---|
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 | 权重处理 |
我们只需要掌握Path这种路由工程就可以了。
4路由过滤器 GatewayFilter
GatewayFilter是网关中提供的一种过滤器,可以对进入网关对的请求和微服务返回的响应做处理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ac8lIb8p-1693053166329)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826192508895.png)]
4.1路由过滤器的种类
Spring提供了31种不同的路由过滤器工厂。例如:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
4.2请求头过滤器
以AddRequestHeader为例讲解
需求:给所有进入userservice的请求添加一个请求头
实现方法:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 #nacos地址
gateway:
routes:
- id: user-service #路由标识,必须唯一
uri: lb://userservice
predicates: #判断请求是否符合规则
- Path=/user/** #路径断言,判断路径是否以/user开头,如果是则符合
filters:
- AddRequestHeader=wuhu,qifei #添加请求头
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。
4.3默认过滤器
如果要对所有的路由都生效,则可以将过滤器工厂写到default下
default-filters:
- AddRequestHeader=wuhu,qifei #添加请求头
4.4自定义全局过滤器
案例:定义全局过滤器,拦截请求,判断请求的参数是否满足以下条件
- 参数中是否含有authorization
- authorization参数值是否为admin
如果同时满足则放行,否则拦截
在gateway中添加一个过滤器的类
@Component
//@Order(0) //顺序值,默认值21亿,值越小,优先级越高,负21亿优先级最高
public class AutherizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求参数
ServerHttpRequest request = exchange.getRequest();
//获取参数中的authorization参数
MultiValueMap<String, String> params = request.getQueryParams();
//判断参数值是否等于admin
String auth = params.getFirst("authorization");
if ("admin".equals(auth)) {
//相等 放行
return chain.filter(exchange);
}
//不等 拦截
//设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//未登录401
//拦截请求
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return -1;
//顺序值,默认值21亿,值越小,优先级越高,负21亿优先级最高
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkwmCRFi-1693053166329)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826195722743.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3W3S89hI-1693053166330)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826195733211.png)]
4.5过滤器执行顺序
请求进入网关会碰到三类过滤器:当前路由过滤器,DefaultFilter,GlobalFilter
请求路由后,会将当前路由过滤器和DefaultFilter和GlobalFilter合并到一个过滤链(集合)中,排序后依次执行每个过滤器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FPvSmIp-1693053166330)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826200143527.png)]
排序规则:
- 每一个过滤器都必须指定一个int类型的order值,order月小,优先级越高,执行顺序越靠前
- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
- 路由过滤器和defaultFilter的order值由spring指定,默认按照声明的顺序从1开始递增
- 当过滤器的order值一样时,按照defaultFIlter>路由过滤器>GlobalFilter的顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7SROn6YG-1693053166331)(C:\Users\19627\AppData\Roaming\Typora\typora-user-images\image-20230826200820143.png)]
4.6gateway跨域问题处理
跨域问题:域名不一致就是跨域,主要包括;
- 域名不同:www.taobao.com和ww.taobao.org www.jd.com和miaosha.jd.com
- 域名相同,端口不同:localhost:8080和localhost:8081
- 跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期