Gateway

 

 

----------------------------------------------------------------------------------------
###################  spring cloud Gateway #########################################

反向代理
鉴权
流量控制
熔断
日志监控

三大核心概念
Route:路由
Predicate:谓词,断言
Filter:过滤器

路由转发+断言判断+执行过滤器链

    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--服务注册发现consul discovery,网关也要注册进服务注册中心统一管控-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>



server:
  port: 9527

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    consul: #配置consul地址
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}



@SpringBootApplication
@EnableDiscoveryClient //服务注册和发现
public class Main9527
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main9527.class,args);
    }
}



http://localhost:8500/

--------------------------


@RestController
public class PayGateWayController
{
    @Resource
    PayService payService;

    @GetMapping(value = "/pay/gateway/get/{id}")
    public ResultData<Pay> getById(@PathVariable("id") Integer id)
    {
        Pay pay = payService.getById(id);
        return ResultData.success(pay);
    }

    @GetMapping(value = "/pay/gateway/info")
    public ResultData<String> getGatewayInfo()
    {
        return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());
    }
}


http://127.0.0.1:8001/pay/gateway/get/3
http://127.0.0.1:8001/pay/gateway/info


server:
  port: 9527

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    consul: #配置consul地址
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由



http://127.0.0.1:9527/pay/gateway/get/3
http://127.0.0.1:9527/pay/gateway/info

--------------------------

@FeignClient(value = "cloud-payment-service")
public interface PayFeignApi
{

    @GetMapping(value = "/pay/gateway/get/{id}")
    public ResultData getById(@PathVariable("id") Integer id);

    @GetMapping(value = "/pay/gateway/info")
    public ResultData<String> getGatewayInfo();

}



@RestController
public class OrderGateWayController
{
    @Resource
    private PayFeignApi payFeignApi;

    @GetMapping(value = "/feign/pay/gateway/get/{id}")
    public ResultData getById(@PathVariable("id") Integer id)
    {
        return payFeignApi.getById(id);
    }

    @GetMapping(value = "/feign/pay/gateway/info")
    public ResultData<String> getGatewayInfo()
    {
        return payFeignApi.getGatewayInfo();
    }
}


http://localhost/feign/pay/gateway/get/1
http://localhost/feign/pay/gateway/info



//@FeignClient(value = "cloud-payment-service")
@FeignClient(value = "cloud-gateway")
public interface PayFeignApi


server:
  port: 9527

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    consul: #配置consul地址
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service           #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由
            - After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai]   # Before # Between
            - Cookie=username,zzyy
            - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            - Host=**.atguigu.com
            - Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
            - RemoteAddr=192.168.0.103/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
            - Method=GET,POST
            - My=gold
            - name: My
              args:
                userType: diamond

        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service           #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

        - id: pay_routh3 #pay_routh3
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
          filters:
            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
            - SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy
            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
            - AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

http://localhost/feign/pay/gateway/get/1
http://localhost/feign/pay/gateway/info


curl http://127.0.0.1:9527/pay/gateway/get/3  --cookie "username=zzyy"

curl http://127.0.0.1:9527/pay/gateway/get/3  -H "X-Request-Id:123456"
curl http://127.0.0.1:9527/pay/gateway/get/3  -H "X-Request-Id:aabbcc"

curl http://127.0.0.1:9527/pay/gateway/get/3  -H "Host:abcxxx.atguigu.com"

curl http://127.0.0.1:9527/pay/gateway/get/3?username=123

http://192.168.0.103:9527/pay/gateway/get/3


//需求说明:自定义配置会员等级userTpye,按照钻/金/银和yml配置的会员等级,以适配是否可以访问
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{

    public MyRoutePredicateFactory()
    {
        super(Config.class);
    }

    //这个Config类就是我们的路由断言规则,重要
    @Validated
    public static class Config
    {
        @Setter@Getter@NotEmpty
        private String userType; //钻/金/银和yml配置的会员等级
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("userType");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config)
    {
        return new Predicate<ServerWebExchange>()
        {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                //检查request的参数里面,userType是否为指定的值,符合配置就通过
                //http://localhost:9527/pay/gateway/get/1?userType=diamond
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
                if (userType == null) {
                    return false;
                }
                //如果说参数存在,就和config的数据进行比较
                if(userType.equalsIgnoreCase(config.getUserType())){
                    return true;
                }
                return false;
            }
        };
    }
}





curl http://127.0.0.1:9527/pay/gateway/get/3?userType=diamond
curl http://127.0.0.1:9527/pay/gateway/get/3?userType=gold


增加请求头过滤器AddRequestHeader

PayGateWayController.java增加代码方法

    @GetMapping(value = "/pay/gateway/filter")
    public ResultData<String> getGatewayFilter(HttpServletRequest request)
    {
        String result = "";
        Enumeration<String> headers = request.getHeaderNames();
        while(headers.hasMoreElements())
        {
            String headName = headers.nextElement();
            String headValue = request.getHeader(headName);
            System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);

            if(headName.equalsIgnoreCase("X-Request-atguigu1")
                    || headName.equalsIgnoreCase("X-Request-atguigu2")) {
                result = result+headName + "\t " + headValue +" ";
            }
        }
        System.out.println("=============================================");
        String customerId = request.getParameter("customerId");
        System.out.println("request Parameter customerId: "+customerId);

        String customerName = request.getParameter("customerName");
        System.out.println("request Parameter customerName: "+customerName);
        System.out.println("=============================================");

        return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());
    }



        - id: pay_routh3 #pay_routh3
          uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
          filters:
            - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
            - AddRequestHeader=X-Request-atguigu2,atguiguValue2
            - RemoveRequestHeader=sec-fetch-site      # 删除请求头sec-fetch-site
            - SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy
            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null
            - AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
            - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
            - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

http://localhost:9527/pay/gateway/filter
http://localhost:9527/pay/gateway/filter?customerId=99999&customerName=zhan3

          predicates:
#            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
             - Path=/gateway/filter/**              # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
          filters:
             - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter  被分拆为: PrefixPath + Path

http://localhost:9527/gateway/filter
http://localhost:9527/gateway/filter?customerId=99999&customerName=zhan3

          predicates:
            - Path=/XYZ/abc/{segment}           # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代
          filters:
            - SetPath=/pay/gateway/{segment}  # {segment}表示占位符,你写abc也行但要上下一致


http://localhost:9527/XYZ/abc/filter


          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
          filters:
            - RedirectTo=302, http://www.atguigu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/


自定义全局过滤器

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered
{
    public static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始调用方法的时间

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        //1 先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME,System.currentTimeMillis());
        //2 返回统计的各个结果给后台
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if(beginVisitTime != null)
            {
                log.info("访问接口主机:"+exchange.getRequest().getURI().getHost());
                log.info("访问接口端口:"+exchange.getRequest().getURI().getPort());
                log.info("访问接口URL:"+exchange.getRequest().getURI().getPath());
                log.info("访问接口URL后面参数:"+exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口时长:"+(System.currentTimeMillis() - beginVisitTime) + "毫秒");
                log.info("============分割线==========================");
                System.out.println();
            }
        }));
    }

    /**
     * 数字越小,优先级越高
     * @return
     */
    @Override
    public int getOrder()
    {
        return 0;
    }
}


http://localhost:9527/pay/gateway/info
http://localhost:9527/pay/gateway/get/3
http://localhost:9527/pay/gateway/filter

自定义条件过滤器



@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    public MyGatewayFilterFactory()
    {
        super(Config.class);
    }


    @Override
    public GatewayFilter apply(Config config)
    {
        return new GatewayFilter()
        {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
            {
                ServerHttpRequest request = exchange.getRequest();
                System.out.println("进入了自定义网关过滤器MyGatewayFilterFactory,status:"+config.getStatus());
                if(request.getQueryParams().containsKey("atguigu")){
                    return chain.filter(exchange);
                }else{
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                    return exchange.getResponse().setComplete();
                }
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("status");
    }

    public static class Config
    {
        @Getter@Setter
        private String status;//设定一个状态值/标志位,它等于多少,匹配和才可以访问
    }
}
//单一内置过滤器GatewayFilter

          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由,默认正确地址
          filters:
            - My=atguigu


http://localhost:9527/pay/gateway/filter
http://localhost:9527/pay/gateway/filter?atguigu=java

----------------------------------------------------------------------------------------

 

 

 

 

posted on 2025-12-21 21:30  yebinghuai-qq-com  阅读(0)  评论(0)    收藏  举报

导航