• SpringCloud Gateway用法详解


    零、人在月球

    目录

    零、人在月球

    一、功能简介

    1、网关是一个服务:

    二、Gateway 断言

    1、path断言

    2、Query断言

    3、Method断言

    4、Host断言

    5、Cookie断言

    6、Header断言

    7、Weight 权重路由

    8、After 时间路由

    9、Before 时间路由

    10、Between时间区间路由

    11、灰度发布

    三、Gateway 过滤器

    1、增加header 请求头

    2、新增动态header请求头

    3、设置请求头 过滤器配置,修改移除请求头

    4、PreserverHostHeader

    5、重写response加密密码

    6、response去重

    7、路径带前缀 请求/get/app 其实是/prefix/get

    8、配置30几 跳转到指定地址

    9、修改状态码

    10、转发地址

    11、去掉增加 请求路径中部分层级

    12、重试过滤器

    13、过滤器设置请求大小

    14、spring-session

    15、默认filter

    四、熔断机制?

    1、老熔断

    2、熔断机制-新的

    五、限流配置

    1、增加依赖

    2、配置redis:spring.redis.database:XX

    3、配置keyResolver,参考类RateLimiteConfig

    4、ym配置spring.cloud.gateway.routes

    5、当发生限流,会向redis存储两个数据 .限流返回状态码是429

    6、配置文件RateLimiteConfig.java

    六、自定义谓词配置类

    1、配置类UserNameCheckRoutePredicateFactory.java

    2、配置项

    七、自定义过滤器

    1、配置类

    pre配置类

    post过滤器

    3、配置文件

    八、全局过滤器

    九、网关超时配置

    十、元数据 metadata

    十一、gateway内置API与跨域

    1、API说明:

    2、打开端点配置

    3、跨域请求:


    一、功能简介

    1、网关是一个服务:
    Spring Cloud GateWay是Spring Cloud的个全新项,标是取代Netflix Zuul,基于Spring5.0+SpringBoot2.0+WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能于Zuul,官测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供种简单有效的统的API路由管理式
    网关:
    一、流量网关
    1、全局性流控 匹配路由 gateway转发前端地址、后端地址、文件服务器、调度器、消息中心 OK!
    2、日志统计 可以统计到所有到前端后端接口 OK
    3、防止SQL注入 – 未使用
    4、防止web攻击 --未使用
    5、屏蔽工具扫描 --未使用
    6、黑白IP名单 通过filter过滤IP禁止访问
    7、证书/加解密处理 --未使用

    二、业务网关
    1、服务级别流控 前端访问后端通过网关 OK!
    2、服务降级和熔断 统一后端接口熔断降级、POST接口限流1s/1次 OK!
    3、路由与负载均衡、灰度的策略 负载均衡OK! 灰度需要部署集群
    4、服务过滤、聚合与发现 通过注册中心,自定义谓词与自定义过滤器 OK!
    5、权限验证与用户等级策略 – 使用app端的权限
    6、业务规则与参数校验 --未使用
    7、多级缓存策略 --未使用

    二、Gateway 断言

    依赖:org.springframework.cloud:spring-cloud-starter-gateway

    父依赖:

    dependencyManagement {
    imports {
    mavenBom “org.springframework.cloud:spring-cloud-dependencies: s p r i n g C l o u d V e r s i o n " m a v e n B o m " c o m . a l i b a b a . c l o u d : s p r i n g − c l o u d − a l i b a b a − d e p e n d e n c i e s : {springCloudVersion}" mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies: springCloudVersion"mavenBom"com.alibaba.cloud:springcloudalibabadependencies:{comAlibabaCloud}”
    }
    }

    断言:predicates 多断言可以配合使用

    1、path断言

    predicates:

    -Path=/mg

    2、Query断言

    参数值可以写正则,也可以只写参数名

    predicates:

    -Query=foo,ba.

    3、Method断言

    predicates:

    -Method=get

    4、Host断言

    predicates:

    -Host=mashibing.com

    5、Cookie断言

    predicates:

    -Cookie=name,yiming

    6、Header断言

    predicates:

    -Header=reqId,9090d+ #正则表达式d+ 数字

    7、Weight 权重路由

    - id: weight2
      uri: http://localhost:6601
      predicates:
        - Path=/api/**
        - Weight=group1,2
      filters:
        - StripPrefix=1
    - id: weight8
      uri: http://localhost:6602
      predicates:
        - Path=/api/**
        - Weight=group1,8
      filters:
        - StripPrefix=1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8、After 时间路由

    #After
          - id: after_route
            uri: lb://micore-test1
            predicates:
              - After=2022-02-07T17:05:00.789+08:00[Asia/Shanghai]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    9、Before 时间路由

    - Before=2022-02-07T17:05:00.789+08:00[Asia/Shanghai]
    
    • 1

    10、Between时间区间路由

    - Between=2021-02-07T17:05:00.789+08:00[Asia/Shanghai],2022-02-07T17:05:00.789+08:00[Asia/Shanghai]
    
    • 1

    11、灰度发布

    同一个请求地址,设置多个url也就是多个服务。比如M5,和MD5 两个服务,比重设置95%和5%。先升级一部分的服务,再切换另一个服务进行升级。

    三、Gateway 过滤器

    1、增加header 请求头

    附加:代码中获取请求头 JSONView插件

    spring.cloud.gateway.routes
    -id: add_request_header
    uri: lb://test-prod
    predicates: 
        -Path= /getheader
    filters:
        #增加请求头、请求参数
        -AddRequestHeader= X-Request-id, 99999
        -AddRequestHeader= X-Request-author, kevin
        -AddRequestParameter= param-id,99999
        -AddRequestParameter= param-author, kevin
        -AddResponseHeader=rep-id, 99999
        -AddResponseHeader=req-author,kevin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    java代码获取header 和请求参数param 和response

    @GetMapping("getHeaders")
    public Map getHeaders(HttpServletRequest request){
        Map map =new HashMap<>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = request.getHeader(name);
            map.put(name,value);
        }
        return map;
    }
    
    @GetMapping("getParameter")
    public Map getparam(HttpServletRequest request){
        Map paramMap=request.getParameterMap();
        return paramMap;
    }
    
    @GetMapping("getResponseHeader")
    public Map> getheader3(HttpServletResponse response){
        response.addHeader("req-id","123456");
        response.addHeader("req-id","1234567");
        response.addHeader("rep-url","/42?user=ford&paddwd=omg!what&flag=true");
        Map>map=new HashMap<>();
        Collection headerNames=response.getHeaderNames();
        for(String name:headerNames){
            Collection headers=response.getHeaders(name);
            map.put(name,headers);
        }
        return map;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2、新增动态header请求头

    predicates:
        -Path= /getheader/{seq}
    filters:
        -AddRequestHeader= X-Request-id, 99999-{seq}
        -AddRequestHeader= X-Request-author, kevin-{seq}
        -AddRequestParameter= param-id,99999-{seq}
        -AddRequestParameter= param-author, kevin-{seq}
        -AddResponseHeader=rep-id, 99999-{seq}
        -AddResponseHeader=req-author,kevin-{seq}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    方法:@GetMapping(“getHeader/{param}”)

    3、设置请求头 过滤器配置,修改移除请求头

    #设置请求头,没有则新增,有则修改
    -SetRequestHeader=X-Request-id,9999
    #移除请求头、请求参数
    -RemoveRequestHeader= X-Request-id
    -RemoveRequestParameter=X-Request
    -RemoveRequestParameter=X-Request-author
    #先从header取from-Header,如果有则赋值给to-Header,如果没from-Header则无效果
    -MapRequestHeader=from-Header,to-Header
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、PreserverHostHeader

    #默认开启,在gateway转发请求前把原始请求的host头部带上,转发给目的服务

    -PreserverHostHeader
    
    • 1

    5、重写response加密密码

    #例如: req-url=/42user=ford&passwd=omg!what&flag=true 经过下面配置替换为/42user=ford&passwd=***&flag=true

    -RewriteResponseHeader=req-url,passwd=[^&]+,passwd=***
    
    • 1

    6、response去重

    RETAIN_FIRST保留第一个

    RETAIN_LAST保留最后一个

    RETAIN_FIRST RETAIN_UNIQUE 保留唯一

    -DedupeResponseHeader= req-id,RETAIN_FIRST
    
    • 1

    7、路径带前缀 请求/get/app 其实是/prefix/get

    -PrefixPath= /prefix
    
    • 1

    8、配置30几 跳转到指定地址

    #300 Multiple多种选择,请求的资源可能包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端选择

    #301 Moved Permanently永久移动,请求的资源已被永久移动新位置,返回信息会包含URI,浏览器会自动定向到新地址,以后请求应该用新的URI代替

    #302 Found 临时移动,与301类似,资源临时被移动,客户端应该继续使用原URI

    #303See Other查看其它地址,与301类似。使用GET和POST请求查看

    #304未修改,所请求资源未修改,服务器返回此状态吗时,不会返回任何资源

    #305Use proxy 使用代理,所请求资源必须通过代理

    #306 Unused 已经废弃的HTTP状态码

    #307 Temporary Redirect 临时重定向,与302类似,使用GET请求重定向

    ? -RedirectTo=302,http://www.baidu.com 
    
    -RedirectTo=301,http://www.taobao.com
    ?
    
    • 1
    • 2
    • 3
    • 4

    9、修改状态码

    #修改状态码,可以org.springframework.http.HttpStatus枚举,也可以直接写状态码

    -SetStatus=NOT_FOUND
    -SetStatus=404
    
    • 1
    • 2

    10、转发地址

    #访问/api/getheader 实际访问:/getheader,转发的目的地址必须写 / 否则会出错

    -RewritePath=/api/getheader, /getheader
    
    • 1

    #http://192.168.31.80:8801/www/get/user/12123 实际访问:/prefix/get/user/12123

    #http://192.168.31.80:8801/www/getheader 实际访问:/prefix/getheader

    -RewritePath=/www/(?/?.*), /prefix/${segment}
    
    • 1

    转发例子2 例如请求/profix/get/user/12123 实际请求是 /get/user

    predicates:
        -Path=/prefix/{var1}/{var2}/{var3}
    filter:
        -SetPath=/{var1}/{var2}
    
    • 1
    • 2
    • 3
    • 4

    11、去掉增加 请求路径中部分层级

    #请求/api/get/123 实际请求/get/123

    -StripPrefix=1 从前往后去掉一些路径
    
    • 1

    #请求/get/123 实际请求/prefix/get/123

    -PrefixPath=/prefix 增加前缀路径
    
    • 1

    12、重试过滤器

    predicates:
        -Path=/testRetry
    filters:
        - name:  Retry  #过滤器名称
          args:
            retries: 3 #重试次数
            series: #org.springframework.http.HttpStatus.Series 枚举 什么类型状态码进行重试
                -SERVER_ERROR
                -CLIENT_ERROR
            statuses:#org.springframework.http.HttpStatus枚举值,什么状态码重试
                -BAD_GATEWAY
                -METHOD_NOT_ALLOWED
            methods: #什么类型方法重试
                -GET
                -POST
            exception: #什么异常进行重试
                -java.io.IOException
            backoff:#重试时间间隔
                firstBackoff: 10ms
                maxBackoff: 50ms
                factor: 2
                basedOnPreviousValue: false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    13、过滤器设置请求大小

    filters:
        -name: RequestSize #过滤器名称
         args:   #控制请求的大小,超过则返回413.请求最大默认5000000 约5M
            maxSize:1000  #1KB
    
    • 1
    • 2
    • 3
    • 4

    14、spring-session

    filters:
    #只有当集成Spring Session才会将session放到Redis,来实现共享Session功能,如果项目继承了Spring Session中的Spring Security框架。如果希望安全验证信息可以转发到远程应用,那么这个配置是必须的
        - SaveSession
    
    • 1
    • 2
    • 3

    15、默认filter

    spring.cloud.gateway.default-filters:
        -AddRequestHeader=X-Request-Default, Gateway
    
    • 1
    • 2

    四、熔断机制

    1、老熔断

    ①增加依赖包:org.springframework.cloud:spring-cloud-starter-netflix-hystrix

    ②默认熔断配置

    spring.cloud.gateway
    default-filters:
        -name: Hystrix #设置默认熔断器
         args:
            name: fallback1 #熔断器名字,随便起
            fallbackUrl: forward:/fallbackHysrix  //发生熔断后跳转的地址
    #设置hystrix断路器超时时间
    hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMillliseconds:2000  #2秒
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该地址:需要在gateway项目中新增一个controller com.longze.controller.FallbackController

    @RestController
    public class FallbackController {
        @RequestMapping("/fallbackHysrix")
        public String fallbackHysrix(){
            return "fallbackHystrix error";
        }
        @RequestMapping("/fallbackCircuitBreaker")
        public String fallbackCircuitBreaker(){
            return "fallbackCircuitBreaker error";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ③单独配置熔断器

    spring.cloud.gateway.routes
    filters:
        -name: Hystrix #设置熔断器
         args:
            name: fallbackcmd #熔断器名字,无所谓
            fallbackUri: forward:/fallbackHysrix #熔断之后跳转,本项目或其他项目配置
    #熔断项目在其他项目中
    -id: Hystrix-fallback
    uri: http://localhost:9100
    predicates:
        -Path: /fallbackHysrix
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、熔断机制-新的

    ①增加依赖包:org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j

    和 org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j

    ②#开启resilience4j熔断

    spring.cloud.circuitbreaker.resilience4j.enabled: true
    
    • 1

    ③配置熔断 和Hystrix很相似

    spring.cloud.gateway.routes

    filters:
        -name: CircuitBreaker #设置熔断器
         args:
            name: testCircuitBreaker #熔断器名字,无所谓
            fallbackUri: forward:/fallbackCircuitBreaker #熔断之后跳转,本项目或其他项目配置
    
    • 1
    • 2
    • 3
    • 4
    • 5

    五、限流配置

    1、增加依赖

    org.springframework.boot:spring-boot-starter-data-redis-reactive

    org.springframework.boot:spring-boot-starter-data-redis version: ‘2.5.4’

    2、配置redis:spring.redis.database:XX

     spring
         redis:
            host: 1.2.3.4
            port: 6379
            password: redispassword
            pool:
              max-active: 8
              max-wait: -1
              max-idle: 8
              min-idle: 0
            timeout: 30000
            database: 5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3、配置keyResolver,参考类RateLimiteConfig

    4、ym配置spring.cloud.gateway.routes

    -id: rate-limit-demo
    uri: lb://mima-cloud-producer
    predicates:
        -Path=/rate/**
    filters:
        -name: RequestRateLimiter
         args:
            #令牌桶每秒平均速率,允许用户每秒处理多少个请求
            redis-rate-limiter.replenishRate:1
            #令牌桶的容量,允许在1s内完成的最大请求数
            redis-rate-limiter.burstCapacity:2
            #使用Spel表达式从Spring容器中获取Bean对象,查看RateLimiteConfig实现类中同名方法
            key-resolver: "#{@pathKeyResolver}"
            #key-resolver: "#{@ipKeyResolver}"
            #key-resolver: "#{@userKeyResolver}"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5、当发生限流,会向redis存储两个数据 .限流返回状态码是429

    request_rate_limiter.{key}.timestamp

    request_rate_limiter.{key}.tokens

    timestamp:存储的是当前时间秒数,也就是System.currentTimeMillis()/1000

    tokens:存储的当前这秒钟对应的可用令牌数

    6、配置文件RateLimiteConfig.java

    package com.pig4cloud.pig.demo.controller;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * @Auther: fengqx
     * @Date: 2022/1/2 - 01 -02 - 22:36
     * @Description: 限流配置
     * @Version: 1.0
     */
    @Configuration
    public class RateLimiteConfig{
    
        //ip限流  1s 100次
        //userId限流 1s 100次
        //路径限流
        @Bean
        @Primary  #如果不使用 @Primary 注解,项目启动会报错
        public KeyResolver pathKeyResolver(){
            //写法1
    //        return exchange-> Mono.just(
    //                exchange.getRequest()
    //                .getPath()
    //                .toString()
    //        );
            //写法2
            return new KeyResolver(){
                @Override
                public Mono resolve(ServerWebExchange exchange){
                    return Mono.just(exchange.getRequest()
                    .getPath()
                    .toString());
                }
            };
        }
        //根据请求IP限流
        @Bean
        public KeyResolver ipKeyResolver(){
            return exchange -> Mono.just(
                    exchange.getRequest()
                    .getRemoteAddress()
                    .getHostName()
            );
        }
        //根据userid限流
        @Bean
        public KeyResolver userKeyResolver(){
            return exchange -> Mono.just(
                    exchange.getRequest()
                    .getQueryParams()
                    .getFirst("userId")
            );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    六、自定义谓词配置类

    可以保存数据库,存储。

    1、配置类UserNameCheckRoutePredicateFactory.java

    package com.pig4cloud.pig.demo.util;
    
    import com.mysql.cj.util.StringUtils;
    import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.server.ServerWebExchange;
    
    import javax.validation.constraints.NotEmpty;
    import java.util.function.Predicate;
    
    /**
     * @Auther: fengqx
     * @Date: 2022/1/2 - 01 -02 - 23:20
     * @Description: 自定义谓词,请求入参包含指定userName
     * @Version: 1.0
     */
    @Component
    public class UserNameCheckRoutePredicateFactory extends AbstractRoutePredicateFactory {
    
        public UserNameCheckRoutePredicateFactory(){
            super(Config.class);
        }
        @Override
        public Predicate apply(UserNameCheckRoutePredicateFactory.Config config) {
            //写法1
            return new Predicate() {
                @Override
                public boolean test(ServerWebExchange exchange) {
                    String userName = exchange.getRequest().getQueryParams().getFirst("userName");
                    if(StringUtils.isNullOrEmpty(userName)){
                        return false;
                    }
                    //检查请求参数中userName是否与配置的数据相同,如果相同则允许访问,否则不允许访问
                    if(userName.equals(config.getName())){
                        return true;
                    }
                    return false;
                }
            };
        }
    
        @Validated
        public static class Config{
            @NotEmpty
            private String name;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    2、配置项

    spring.cloud.gateway
    routes:
        -id: Auth_route
         uri: lb://mima-cloud-producer
         order:1
         predicates:
            -Path= /**
            #name配置为UserNameCheckRoutePredicateFactory自定义谓词配置类前缀UserNameCheck, 只有     访问http://192.168.1.10:8081/getheader?userName=Kevin,否则为404
            #必须写在userName请求参数,并且值为kevin
            -name=UserNameCheck
             args:
                name: kevin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    七、自定义过滤器

    1、配置类

    pre配置类

    package com.pig4cloud.pig.demo.util;
    
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.constraints.NotEmpty;
    
    /**
     * @Auther: fengqx
     * @Date: 2022/1/3 - 01 -03 - 10:48
     * @Description: 自定义过滤器 -Pre过滤器
     * @Version: 1.0
     */
    @Component
    public class MyAddRequestHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory {
        public MyAddRequestHeaderGatewayFilterFactory(){super(Config.class);}
    
        @Override
        public GatewayFilter apply(Config config){
            //写法一
    //        return new GatewayFilter() {
    //            @Override
    //            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    //                System.out.println("MyAddRequestHeaderGatewayFilterFactory.apply is run...");
    //                //exchange.getRequest().mutate() //目的是转化为装饰类,否则request为只读的,不能操作
    //                //header方法用来设置header的值
    //                ServerHttpRequest request = exchange.getRequest().mutate().header(config.getName(),config.getValue()).build();
    //                //将request包裹继续向下传递
    //                return chain.filter(exchange.mutate().request(request).build());
    //            }
    //        }
            return (exchange, chain) -> {
                System.out.println("MyAddRequestHeaderGatewayFilterFactory.apply is run...");
                //exchange.getRequest().mutate() //目的是转化为装饰类,否则request为只读的,不能操作
                //header方法用来设置header的值
                ServerHttpRequest request=exchange.getRequest().mutate().header(config.getName(),config.getValue()).build();
                return chain.filter(exchange.mutate().request(request).build());
                 //response可以直接写
    //            exchange.getResponse().getHeaders().set(config.getName(),config.getValue());
    //            return chain.filter(exchange);
            };
        }
    
        @Validated
        public static class Config{
            @NotEmpty
            private String name;
            @NotEmpty
            private String value;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                this.value = value;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    post过滤器

    @Component
    public class PostLogGatewayFilterFactory extends AbstractGatewayFilterFactory {
        @Override
        public GatewayFilter apply(Object config){
            return (exchange, chain) -> {
                return chain.filter(exchange).then(Mono.fromRunnable(()-> {
                    System.out.println("PostLogGatewayFilterFactory is run...");
                }));
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、配置文件

    spring.cloud.gateway.routes
    -id: MyFilter
    uri: lb://mima-cloud
    order: 1
    predicates:
        -Path=/**
    filters:
        -name: MyAddRequestHeader  #Pre过滤器
         args:
            name: req-kevin-header
            value: req-yin.hl
        -name: PostLogGateway  #Post过滤器
    效果,所有请求增加一个header
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    八、全局过滤器

    配置文件不需要配置,只需要增加GlobalFilterConfig 类,即可执行到全局过滤

    package com.pig4cloud.pig.demo.util;
    
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import reactor.core.publisher.Mono;
    
    /**
     * @Auther: fengqx
     * @Date: 2022/1/3 - 01 -03 - 21:23
     * @Description: 全局过滤器
     * @Version: 1.0
     */
    @Configuration
    public class GlobalFilterConfig {
        //order 越小,越先执行
        @Bean
        @Order(-1)
        public GlobalFilter globalFilter1(){
            return (exchange, chain) -> {
                System.out.println("pro filter globalFilter1...");
                return chain.filter(exchange).then(Mono.fromRunnable(()->{
                    System.out.println("post filter globalFilter1...");
                }));
            };
        }
        @Bean
        @Order(1)
        public GlobalFilter globalFilter2(){
            return (exchange, chain) -> {
                System.out.println("pro filter globalFilter2...");
                return chain.filter(exchange).then(Mono.fromRunnable(()->{
                    System.out.println("post filter globalFilter2...");
                }));
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    应答顺序为:pro filter globalFilter1…

    pro filter globalFilter2…

    post filter globalFilter2…

    post filter globalFilter1…

    九、网关超时配置

    spring.cloud.gateway.httpclient.connect-timeout=1000 #连接超时 毫秒

    spring.cloud.gateway.httpclient.response-timeout=5s #应答超时 java.time.Duration http状态码504

    十、元数据 metadata

    十一、gateway内置API与跨域

    0、依赖

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    
    • 1

    1、API说明:

    /actuator/gateway/routes/{id} ,method=[DELETE] 删除单个路由

    /actuator/gateway/routes/{id},method=[POST] 新增单个路由

    /actuator/gateway/routes/{id},method=[GET] 查看单个路由

    /actuator/gateway/routes ,method=[GET] 查看路由列表

    /actuator/gateway/refresh,method=[POST] 路由刷新

    /actuator/gateway/globalfilters,method=[GET]获取全局过滤器列表

    /actuator/gateway/routefilters,method=[GET] 路由过滤器工厂列表

    2、打开端点配置

    management.endpoint.gateway.enabled=true
    management.endpoints.web.exposure.include=gateway
    
    • 1
    • 2

    3、跨域请求:

    配置文件-直接引用即可

    package com.pig4cloud.pig.demo.util;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.web.cors.reactive.CorsUtils;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.server.WebFilter;
    import org.springframework.web.server.WebFilterChain;
    import reactor.core.publisher.Mono;
    /**
     * @Auther: fengqx
     * @Date: 2022/1/3 - 01 -03 - 22:03
     * @Description: 跨域配置
     * http://vvv.mekebin.com/123  ajax-> http://vvv.mekebin.com/123/test 不跨域
     * http://vvv.mekebin.com/123  ajax-> http://def.mekebin.com/123/test 跨域
     * http://vvv.mekebin.com:8801/123  ajax-> http://vvv.mekebin.com:9901/123/test 跨域
     * http://vvv.mekebin.com/123  ajax-> https://vvv.mekebin.com/123/test 跨域
     * @Version: 1.0
     */
    @Configuration
    public class CorsConfig {
        private static final String MAX_AGE="18000L";
     
        @Bean
        public WebFilter corsFilter(){
            return (ServerWebExchange ctx, WebFilterChain chain)->{
                System.out.println("corsFilter...  run");
                ServerHttpRequest request = ctx.getRequest();
                if(!CorsUtils.isCorsRequest(request)){
                    return chain.filter(ctx);
                }
                HttpHeaders requestHeaders=request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod= requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers=response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlAllowHeaders());
                if(requestMethod!=null){
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,requestMethod.name());
                }
                //携带cookie
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,"*");
                headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
                if(request.getMethod() == HttpMethod.OPTIONS){
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
                return chain.filter(ctx);
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    荆轲刺秦王!

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    Python学习笔记——类、魔术方法
    【20221201】【每日一题】划分字母区间
    Rust嵌入式编程---动态内存分配器(Vec,String等)
    【Python】基础知识
    DAO:OP 代币和不可转让的 NFT 致力于建立新的数字民主
    git常用命令以及多人操作同一文件解决冲突的方法
    Vue官方文档(48): vuex的基本使用
    内核与协议无关接口层的实现
    UnityPackageManager相关
    Flow 3D学习记录
  • 原文地址:https://blog.csdn.net/m0_67392661/article/details/126116187