7.统一网关Gateway
7.1 概述


阻塞式编程:阻塞式编程是指当一个线程执行一个任务时,它会一直等待直到任务完成并返回结果,期间无法执行其他任务。这种编程模型会导致线程的资源浪费和系统响应时间的延迟,尤其在I/O密集型应用中表现明显。在阻塞式编程中,当一个请求到达时,处理该请求的线程将被阻塞直到请求处理完成并响应,而在此期间,该线程无法处理其他请求。
响应式编程:相比之下,响应式编程是一种基于事件驱动的编程模型,它通过使用异步非阻塞的方式来处理任务。在响应式编程中,当一个请求到达时,处理该请求的线程不会被阻塞,而是将请求发送给异步处理程序,该程序在处理请求时不会阻塞线程,并在处理完成后通知处理结果。这样可以充分利用系统资源,提高系统吞吐量和响应速度,尤其在处理大量并发请求时表现更加出色。
响应式编程的核心思想是数据流,即数据在程序中的传递方式。在响应式编程中,数据流由一系列的事件组成,每个事件都有一个时间戳和一个数据值。开发人员可以使用各种操作符来组合和转换这些事件,从而实现各种复杂的逻辑处理。响应式编程常用的框架包括RxJava、Reactor、Vert.x等。
7.2 快速入门
1.新建gateway子模块,pom文件引入依赖
<dependencies>
<!--Nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-Nacos-discovery</artifactId>
</dependency>
<!--gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
2.创建GatewayApplication
@SpringBootApplication
public class GatewayApplication(){
public static void main(String[] args){
SpringApplication.run(GatewayApplication.class,args);
}
}
3.编写配置文件,配置gateway端口号;服务名称;Nacos地址;路由配置id/uri/predicates
server:
port: 10010
spring:
application:
name: gateway
cloud:
Nacos:
server-addr: localhost:8848
gateway:
routes:
- id: user-service # 路由标识,必须唯一,不一定要和服务名一致
#路由的目标地址,lb表示启用负载均衡,//表示服务名称
# uri也可以直接写http地址,但一般不采用
uri: lb://user-service
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,若请求以user开头则转发至user-service
⭐使用Gateway地址访问报错503 service unavailable
bug:使用localhost:10010访问资源时报503错误,控制台日志也显示service=null
思考:明显可以看出是service没有正确获取到,检查发现service名称没有写错,重新思考;一定是gayeway的配置文件yml出了问题,检查发现uri部分使用了负载均衡,根据先前的开发经验,spring-cloud最新版已经弃用了ribbon,没有内置负载均衡器了,所以要使用负载均衡需要引入loadbalancer依赖
debug:在gateway模块的pom文件中添加如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
7.3 路由断言工厂Route Predicate Factory
作用:解析配置文件中的断言规则predicates


eg.在路由断言中添加过滤条件
spring:
cloud:
gateway:
routes:
- id: user-service # 路由标识,必须唯一,不一定要和服务名一致
uri: lb://user-service #路由的目标地址,lb表示启用负载均衡,//表示服务名称
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,若请求以user开头则转发至user-service
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
- After=2071-01-20T17:42:47.789-07:00[America/Denver] #该路由匹配 2017 年 1 月 20 日 17:42 山地时间(丹佛)之后提出的任何请求。
参考官方文档
效果:user可以正常访问,但order报错404

7.4 路由的过滤器配置

参考官方文档,spring-cloud gateway一共提供了30种过滤器,官方文档给出了每种过滤器的作用和使用方法.
spring:
cloud:
gateway:
routes:
- id: user-service # 路由标识,必须唯一,不一定要和服务名一致
uri: lb://user-service #路由的目标地址,lb表示启用负载均衡,//表示服务名称
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,若请求以user开头则转发至user-service
# 只对当前部分的请求有效
filters:
- AddRequestHeader=MyHeaderKey,my header value
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
- After=2071-01-20T17:42:47.789-07:00[America/Denver]
# 对所有请求都有效
default-filters:
- AddRequstHeader=MyHeaderKey, my header value
获取示例:
@GetMapping("/{id}")
public Result queryById(@PathVariable("id") Long id,@RequestHeader(required = false) String header) {
User user = userService.queryById(id);
System.out.println("now user------"+user);
String msg = null!=user?"":"查询失败";
System.out.println("header: "+header);
return new Result(null!=user? Code.GET_OK:Code.GET_ERR,user,msg);
}
7.5 全局过滤器
global-filter和default-filters不同:
全局过滤器对所有路由都生效.


实例:

1.编写filter类(exchange是flask风格)
//@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter , Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
//2.获取参数并判断
String auth = params.getFirst("authorization");
if("admin".equals(auth)){
//3.是,放行
return chain.filter(exchange);
}
//4.否,拦截(直接拦截用户体验不好,所以设置一下状态码)
//4.1 设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//4.2拦截请求
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
//当有多个拦截器时,需要根据order的value判断拦截器的执行顺序,数字越小优先级越大
//也可以直接通过添加order注解的方式设置value
return -1;
}
}
2.重启application,只有满足filter条件才能正常访问
http://localhost:10010/user/2?authorization=admin
7.6 过滤器执行顺序


7.7 网关的cors跨域配置
跨域问题处理


- 设置maxAge:跨域允许的有效期,有效期内浏览器可以不再询问服务器是否允许跨域,减轻服务端压力
- [/**]表示拦截一切请求