SpringCloud学习笔记(七)统一网关Gateway

7.统一网关Gateway

7.1 概述

Spring gateway官方文档

image-20230419162121723
image-20230419162655459

阻塞式编程:阻塞式编程是指当一个线程执行一个任务时,它会一直等待直到任务完成并返回结果,期间无法执行其他任务。这种编程模型会导致线程的资源浪费和系统响应时间的延迟,尤其在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

image-20230419210614708
image-20230419210633756

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

image-20230419220003505

7.4 路由的过滤器配置

Spring Cloud Gateway Diagram

参考官方文档,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不同:

全局过滤器对所有路由都生效.

image-20230419221431200
image-20230419221617268

实例:

image-20230419221703338

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 过滤器执行顺序

image-20230420094537163
image-20230420094950953

7.7 网关的cors跨域配置

跨域问题处理

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

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注