栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringCloud-Gateway网关学习和实战

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringCloud-Gateway网关学习和实战

SpringCloud-Gateway网关学习和实战 1.Gateway概述 1.1 什么是Gateway

上一代zuul 1.x官网

Gateway官网

Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;

但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway—句话:gateway是原zuul1.x版的替代

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fuLsvolV-1653224498500)( https://com-qianyue-img.oss-cn-hangzhou.aliyuncs.com/img/54b61d819aa1630bc61732de340b55b4.png)]

Gateway是在Spring生态系统之上构建的API网关服务,由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中

工作,也不能构建成 war 包

1.2 Gateway可以干什么

Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的 基本功能,例如说安全认证、监控、限流等等。

1.3 Gateway在微服务架构中的位置

1.4 Gateway核心组件

三大核心概念

Route(路由) - 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由;
Predicate(断言) - 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由;
Filter(过滤) - 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改(此过滤非SpringMVC的过滤器)。

1.5 Gateway的基本原理

1.客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关Web 处理程序,此时处理程序运行特定的请求过滤器链。

2.过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。

2.Gateway实战 2.1 环境搭建

1.新建网关模块,添加依赖

    
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        

        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            org.projectlombok
            lombok
            1.18.10
        
    

2.yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      enabled: true #是否开启网关

3.添加主启动类

@SpringBootApplication
public class MallGatewayApplication8888 {

    public static void main(String[] args) {
        SpringApplication.run(MallGatewayApplication8888.class,args);
    }
}
2.2 实战操作 2.3.1 通过微服务名称调用

(1).配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关

(2).测试 访问http://localhost:8888/mall-order/order/findOrderByUserId/1,这种方式太low了我们是不希望微服务名称暴漏的。

2.3.2 路由加断言

Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个RoutePredicate工厂可以进行组合。Spring Cloud Gateway创建Route 对象时,使用RoutePredicateFactory 创建 Predicate对象,Predicate 对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。

常用的Route Predicate Factory

The After Route Predicate Factory
The Before Route Predicate Factory
The Between Route Predicate Factory
The Cookie Route Predicate Factory
The Header Route Predicate Factory
The Host Route Predicate Factory
The Method Route Predicate Factory
The Path Route Predicate Factory
The Query Route Predicate Factory
The RemoteAddr Route Predicate Factory
The weight Route Predicate Factory

下边以其中几个常用的断言演示下效果

1.Path断言

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order
@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory {

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

    @Override
    public Predicate apply(Config config) {
        return new GatewayPredicate() {

            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                log.info("调用CheckAuthRoutePredicateFactory" + config.getName());
                if("auth".equals(config.getName())){
                    return true;
                }
                return false;
            }
        };
    }

    
    @Override
    public List shortcutFieldOrder() {
        return Collections.singletonList("name");
    }

    
    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

2.yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order
@RestController
@RequestMapping("/order")
@Slf4j
public class GatewayController {

    
    @GetMapping("/testgateway")
    public String testGateway(HttpServletRequest request) throws Exception {
        log.info("gateWay获取请求头X-Request-color:"
                +request.getHeader("X-Request-color"));

        String color = request.getParameter("color");
        log.info("gateWay获取请求参数color:"
                +color);
        return "success";
    }
    @GetMapping("/testgateway2")
    public String testGateway(@RequestHeader("X-Request-color") String color) throws Exception {
        log.info("gateWay获取请求头X-Request-color:"+color);
        return "success";
    }
    @GetMapping("/testgateway3")
    public String testGateway3(@RequestParam("color") String color) throws Exception {
        log.info("gateWay获取请求参数color:"+color);
        return "success";
    }

}

(2)在gateway网关层添加配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (exchange, chain) -> {
            log.info("调用CheckAuthGatewayFilterFactory==="
                    + config.getName() + ":" + config.getValue());
            // TODO
            return chain.filter(exchange);
        };
    }
}

(2)yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order
@Configuration
public class GatewayConfiguration {


    private final List viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}

4.配置流控规则 访问http://127.0.0.1:8888/order/findOrderByUserId/1 在sentinel控制台配置流控规则 可以看出此时的资源名称就是我们的route-id

5.测试 快速访问访问http://127.0.0.1:8888/order/findOrderByUserId/1 说明我们流控成功。

2.3.5.2 手动配置流控规则

(1)编写配置类

@Configuration
public class GatewayConfiguration {


    private final List viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }


    @PostConstruct
    public void doInit() {
//        //初始化自定义的API
        initCustomizedApis();
//        //初始化网关限流规则
        initGatewayRules();
//        //自定义限流异常处理器
        initBlockRequestHandler();
    }



    private void initCustomizedApis() {
        Set definitions = new HashSet<>();
        // 资源保护名user_service_api    Path:/user/**
        ApiDefinition api = new ApiDefinition("user_service_api")
                .setPredicateItems(new HashSet() {{
                    add(new ApiPathPredicateItem().setPattern("/user/**")
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    private void initGatewayRules() {
        Set rules = new HashSet<>();
        //resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
        //count:限流阈值
        //intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
        rules.add(new GatewayFlowRule("user_service_api")
                .setCount(2)
                .setIntervalSec(1)
        );

        // 加载网关规则
        GatewayRuleManager.loadRules(rules);
    }

    private void initBlockRequestHandler() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono handleRequest(ServerWebExchange exchange, Throwable t) {
                HashMap result = new HashMap<>();
                result.put("code",String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
                result.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());

                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(result));
            }
        };
        //设置自定义异常处理器
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

(2)访问127.0.0.1:8888/user/findOrderByUserId/1 查看控制台

3.测试 快速点击127.0.0.1:8888/user/findOrderByUserId/1 出现降级

其实我们在流控规则控制台查看并没有我们手动设置的流控规则,这是一个坑,是因为我们应该导入另外一个包就可以配置

2.3.5.3 Gateway整合Sentinel

1.pom 把上边的适配包去掉 更换为整合包

        
		
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel-gateway
        

2.重新启动Sentinel控制台,发现我们的菜单发生改变

3.配置流控规则,界面也和我们之前的界面不一样

4.新增一个API流控规则

添加API分组

添加流控规则

5.测试 访问127.0.0.1:8888/user/findOrderByUserId/1 流控成功

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/927156.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号