微服务实战(六) Gateway 网关

本文介绍了SpringCloud Gateway作为微服务网关的作用,包括统一入口、鉴权、路由等功能,并对比了Zuul和Gateway。详细阐述了Gateway的工作原理,如Route、Predicate和Filter。接着展示了如何结合Nacos实现动态路由,包括配置、监听和更新路由的步骤。最后提到了可扩展的限流和负载均衡解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微服务实战(六) Gateway 网关

概述

在微服务众多的服务的治理过程中,服务网关的作用在微服务框架中可以提供统一入口鉴权校验动态路由降低耦合度的功能,关于springcloud的网关有三个,分别是zuul、zuul2和gateway,其中zuul/zuul2是Netflix公司开发的,但是因为zuul的性能不够好,zuul2的开发内部有歧义,所以springcloud便自研了一套网关——gateway。

Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,其目标是替代 Netflix Zuul,它不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控/埋点和限流等。

概念

  • Route

    Route 是网关的基础元素,由 ID、目标 URI、断言、过滤器组成。当请求到达网关时,由 Gateway Handler Mapping 通过断言进行路由匹配(Mapping),当断言为真时,匹配到路由。

  • Predicate

    Predicate 是 Java 8 中提供的一个函数。输入类型是 Spring Framework ServerWebExchange。它允许开发人员匹配来自 HTTP 的请求,例如请求头或者请求参数。简单来说它就是匹配条件。

  • Filter

    Filter 是 Gateway 中的过滤器,可以在请求发出前后进行一些业务上的处理。

工作原理

  1. 客户端向Spring Cloud Gateway发出请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway web hander
  2. Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( “pre” )或之后( “post” )执行业务逻辑。
  3. Filter在"pre” 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

Gateway+Nacos 实现动态路由

添加POM
<!--gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
添加配置
server:
  port: 8080
spring:
  application:
    name: sunnyws-gateway
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 172.16.220.50:8848
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
    gateway:
      discovery:
        locator:
          enabled: true
gateway:
  nacos:
    serverAddr: 172.16.220.50:8848
    namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
    dataId: dynamic-route
    timeout: 5000
添加配置类
  • Nacos配置类
@Data
@ConfigurationProperties(prefix = "gateway.nacos")
public class NacosProperties {

    private String serverAddr;

    private String namespace;

    private String group = "DEFAULT_GROUP";

    private String dataId = "dynamic-route";

    private long timeout = 5000;

}
@Data
public class GatewayRouteList {

    private List<RouteDefinition> routes;

}
  • 从Nacos上初始化路由并动态监听
@Slf4j
@Configuration
public class DynamicRouteNacosConfiguration {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    private NacosProperties nacosProperties;

    @PostConstruct
    public void initRoute() {
        try {
            Properties properties = new Properties();
            properties.put("serverAddr", nacosProperties.getServerAddr());
            properties.put("namespace", nacosProperties.getNamespace());
            ConfigService configService = NacosFactory.createConfigService(properties);
            String content = configService.getConfig(nacosProperties.getDataId(), nacosProperties.getGroup(), nacosProperties.getTimeout());
            log.info("初始化网关路由开始");
            updateRoute(content);
            log.info("初始化网关路由完成");

            //开户监听,实现动态
            configService.addListener(nacosProperties.getDataId(), nacosProperties.getGroup(), new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("更新网关路由开始");
                    updateRoute(configInfo);
                    log.info("更新网关路由完成");
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("加载路由出错:{}", e.getErrMsg());
        }
    }

    /**
    * @description: 更新路由
    * @param content
    * @return void
    **/
    private void updateRoute(String content){
        Yaml yaml = new Yaml();
        GatewayRouteList gatewayRouteList = yaml.loadAs(content, GatewayRouteList.class);
        gatewayRouteList.getRoutes().forEach(route -> {
            log.info("加载路由:{},{}", route.getId(), route);
            routeDefinitionWriter.save(Mono.just(route)).subscribe();
        });
    }
}
  • 添加跨域配置
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // 允许cookies跨域
        config.setAllowCredentials(true);
        // #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedOrigin("*");
        // #允许访问的头信息,*表示全部
        config.addAllowedHeader("*");
        // 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.setMaxAge(18000L);
        // 允许提交请求的方法类型,*表示全部允许
        config.addAllowedMethod("*");
//        config.addAllowedMethod("OPTIONS");
//        config.addAllowedMethod("HEAD");
//        config.addAllowedMethod("GET");
//        config.addAllowedMethod("PUT");
//        config.addAllowedMethod("POST");
//        config.addAllowedMethod("DELETE");
//        config.addAllowedMethod("PATCH");

        org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
                new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}
  • 启动类添加@EnableDiscoveryClient允许注册到Nacos

  • 启动类添加@EnableConfigurationProperties注入Nacos配置

@EnableDiscoveryClient
@SpringBootApplication
@EnableConfigurationProperties(NacosProperties.class)
public class GateWayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GateWayApplication.class,args);
    }
}
Nacos添加配置
  • 根据Nacos配置及需求添加配置

这只是gateway的基本使用,也可结合前面介绍的sentinel和ribbon实现负载均衡和限流。

作者: SunnyWs
链接: https://sunnyws.com/posts/f8ec904c/
来源: SunnyWs’Blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值