当前位置:   article > 正文

06-搭建微服务-Gateway作为网关_gateway 做物理机网关

gateway 做物理机网关

0、前提

在上文的基础上,《05-搭建微服务-Nacos作为注册中心及动态刷新_汐小旅Shiory-CSDN博客


1、为什么使用网关SpringCloud-Gateway?

        目前主流的是微服务,一个项目会有很多服务。这些服务有各自的IP和端口,在没有网关之前,客户端维护IP、端口,管理效率太低。而且在集群的情况下,客户端无法实现负载均衡。
        虽然后来有Nginx可以解决这个问题,但还是存在很多的硬编码。
        而SpringCloud-Gateway,是基于Spring5、SpringBoot2.0和Project Reactor等技术开发的网关,目的是为微服务架构系统提供高性能且简单易用的API路由管理方式。它性能强劲,是第一代网关Zuul的1.6倍;它功能强大,内置很多实用的功能,如:路由、过滤、限流就、监控等...而且易于扩展。
        同时,SpringCloud-Gateway本身也是一个微服务,通过服务名称远程调用其他服务,客户端只需记住网关的IP和端口,需把请求发给Gateway,Gateway做一个路由转发,转发给对应的服务请求即可。

1、SpringCloud-Gateway的位置

        处于客户端和服务群之间,API网关

        客户端---Nginx---API网关---服务群

2、可以做的事:

1、路由转发

2、过滤,比如统一鉴权

3、限流

4、监控

5、....


2、核心概念(组件) 

1、Route(路由)

        路由是构建网关的基本模块,它由ID、目标URI、一系列的断言和过滤器组件,如果断言为true则匹配该路由

2、Predicate(断言、谓词)

        开发人员可匹配Http请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

3、Filter(过滤)

        指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或之后队请求进行修改,比如token验证


3、工作流程 

1、客户端向SpringCloud Gateway发出请求

2、Gateway Handler Mapping中找到与请求相匹配的路由

3、将其发送到Gateway Web Handler

4、Gateway Web Handler再通过指定的过滤器链来将请求发送到实际的服务执行业务逻辑,然后返回(过滤器可能会在发送代理请求之前("pre")或之后("post")执行业务逻辑)。


4、搭建网关 

0、新建Module--cloud-gateway

1、加入依赖 

spring-cloud-starter-gateway 网关,底层基于Netty不要依赖spring-cloud-starter-web。因为spring-cloud-starter-web,是基于SpringMVC的,是servlet编程模型,运行服务器是tomcat,而spring-cloud-starter-gateway,基于Spring WebFlux,是reactor编程模型,运行服务器是netty容器。

  1. <!--gateway网关场景依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--端点监控场景依赖-->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-actuator</artifactId>
  10. </dependency>
  11. <!--Nacos服务注册与发现场景依赖-->
  12. <dependency>
  13. <groupId>com.alibaba.cloud</groupId>
  14. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  15. </dependency>
  16. <!--Nacos配置中心场景依赖-->
  17. <dependency>
  18. <groupId>com.alibaba.cloud</groupId>
  19. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  20. </dependency>
  21. <!--@ConfigurationProperties注解飘红去除-->
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-configuration-processor</artifactId>
  25. </dependency>
  26. <!--lombok-->
  27. <dependency>
  28. <groupId>org.projectlombok</groupId>
  29. <artifactId>lombok</artifactId>
  30. </dependency>

2、编写启动类

  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. /**
  6. * =====================================================
  7. * 网关
  8. * @author 汐小旅Shiory
  9. * @date 2021/12/14 21:24
  10. * =====================================================
  11. */
  12. @Slf4j
  13. @SpringBootApplication
  14. @EnableDiscoveryClient // 服务注册与发现
  15. public class GatewayApplication {
  16. public static void main(String[] args) {
  17. SpringApplication.run(GatewayApplication.class, args);
  18. }
  19. }

3、编写配置文件

1、新建application.yml,配置服务名称和端口

  1. server:
  2. port: 9999
  3. spring:
  4. application:
  5. name: cloud-gateway

2、在Nacos上新建一个配置文件,编写Nacos服务注册与发现配置

  1. spring:
  2. cloud:
  3. nacos:
  4. discovery:
  5. server-addr: 192.168.2.102:8848 # nacos-server的地址
  6. username: nacos # nacos-server用户名
  7. password: nacos # nacos-server密码
  8. namespace: shiory # 命名空间ID
  9. group: DEFAULT_GROUP # 组

 3、新建一个bootstrap.yml,编写Naocs配置中心配置

  1. spring:
  2. cloud:
  3. nacos:
  4. config:
  5. server-addr: 192.168.2.102:8848 # nacos-server的地址
  6. username: nacos # nacos-server用户
  7. password: nacos # nacos-server密码
  8. namespace: shiory # 命名空间ID
  9. group: DEFAULT_GROUP # 组
  10. # 文件名是通过公式来拼接的: ${prefix}-${spring.profiles.active}.${file-extension}
  11. prefix: shiory-gateway # 配置文件名前缀${prefix}
  12. file-extension: yml # 配置文件名扩展${file-extension}
  13. profiles:
  14. active: dev # 配置文件名扩展${spring.profiles.active}

4、路由配置(最终是使用动态路由

查看源码可知,路由是一个数组

注意事项:路由配置多个以后,会从上往下,一旦匹配到上面就不会再去匹配下面。所以如果有"/**",一定要放在最后 

情况1、路由到指定的URL

在Nacos上新建的配置文件中加入下面的内容

  1. spring:
  2. cloud:
  3. # 网关配置
  4. gateway:
  5. discovery:
  6. locator:
  7. # 开启注册中心的路由定位器
  8. enabled: true
  9. # 路由配置
  10. routes:
  11. - id: baidu # ID保证唯一
  12. uri: http://www.baidu.com # 服务地址
  13. predicates:
  14. - Path=/** # 路径匹配规则

启动cloud-gateway服务

访问:localhost:9999,就会跳转到百度页面

访问:localhost:9999/a,就会出现404

        原因:localhost:9999 ===> http://www.baidu.com

                localhost:9999/a ===> http://www.baidu.com/a

情况2:路由到微服务---1、静态路由(有硬编码,IP和端口)

此处的"/**"放到了最后,不然无法匹配到"/demo3/**"

  1. spring:
  2. cloud:
  3. # 网关配置
  4. gateway:
  5. discovery:
  6. locator:
  7. # 开启注册中心的路由定位器
  8. enabled: true
  9. # 路由配置
  10. routes:
  11. - id:cloud-demo3 # ID保证唯一
  12. uri: http://192.168.2.102:7003/ # 服务地址
  13. predicates:
  14. - Path=/demo3/** # 路径断言,多个用逗号隔开
  15. - id: baidu # ID保证唯一
  16. uri: http://www.baidu.com # 服务地址
  17. predicates:
  18. - Path=/** # 路径匹配规则

情况2:路由到微服务---2、动态路由

  1. spring:
  2. application:
  3. name: cloud-gateway
  4. cloud:
  5. # 网关配置
  6. gateway:
  7. discovery:
  8. locator:
  9. # 开启注册中心的路由定位器
  10. enabled: true
  11. # 路由配置
  12. routes:
  13. - id: cloud-demo3 # ID保证唯一
  14. uri: lb://cloud-demo3 # 服务名称 lb,LoadBalance,负载均衡,通过ribbon实现的
  15. predicates:
  16. - Path=/demo3/**,/testNacosRefresh/** # 路径断言,多个用逗号隔开
  17. - id: baidu # ID保证唯一
  18. uri: http://www.baidu.com # 服务地址
  19. predicates:
  20. - Path=/** # 路径匹配规则

访问:localhost:9999/demo3/xxx,就会访问到服务demo3的接口


5、谓词工厂

多个谓词工厂可以并存

1、内置谓词工厂

SpringCloudGateway提供了十来种路由谓词工厂(见官网),为网关实现灵活的转发提供了基石。官网上有使用例子

Spring Cloud Gateway

2、自定义谓词工厂

1、自定义谓词工厂的命名规范:后缀必须是RoutePredicateFactory

2、继承AbstractRoutePredicateFactory<配置的数据类型>


6、过滤器

1、内置过滤器

见官网,局部路由器,只针对某个路由生效。官网上有使用例子

Spring Cloud Gateway

2、自定义局部过滤器

与自定义谓词工厂差不多。局部路由器,只针对某个路由生效

1、命名规范:后缀为GatewayFilterFactory

2、继承AbstractGatewayFilterFactory<配置的数据类型>

  1. // 前处理
  2. chain.filter(exchange)放行
  3. chain.filter(exchange).then()放行,then()中可以处理放行之后要处理的事
  4. then(
  5. Mono.fromRunnable(() -> {
  6. // filter后处理
  7. })
  8. )

3、全局过滤器 

1、内置全局过滤器:官网查看:Spring Cloud Gateway

 2、自定义全局过滤器

步骤:

  1. 1、实现GlobalFilter,Ordered
  2. 2、重写filter方法和getOrder方法
  3. 其中,filter方法负责前处理、后处理;getOrder方法,返回数字越小越先执行
  4. 自定义全局过滤器,比如登录认证过滤器
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  3. import org.springframework.cloud.gateway.filter.GlobalFilter;
  4. import org.springframework.core.Ordered;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.web.server.ServerWebExchange;
  7. import reactor.core.publisher.Mono;
  8. /**
  9. * =====================================================
  10. * 全局Token 过滤器
  11. * @author 汐小旅Shiory
  12. * @date 2021/12/14 22:02
  13. * =====================================================
  14. */
  15. @Slf4j
  16. @Component
  17. public class GlobalAccessTokenFilter implements GlobalFilter, Ordered {
  18. @Override
  19. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  20. log.info("全局过滤器============前执行");
  21. //Mono<Void> mono = chain.filter(exchange); // 直接放行
  22. Mono<Void> mono = chain.filter(exchange).then(// 放行之后再后执行
  23. Mono.fromRunnable(() -> {
  24. log.info("全局过滤器============后执行");
  25. })
  26. );
  27. return mono;
  28. }
  29. // 返回数字越小越先执行
  30. @Override
  31. public int getOrder() {
  32. return -2;
  33. }
  34. }

另一种全局过滤器写法,在启动类中编写

  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.gateway.filter.GlobalFilter;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.core.annotation.Order;
  8. import reactor.core.publisher.Mono;
  9. /**
  10. * =====================================================
  11. * 网关
  12. * @author 汐小旅Shiory
  13. * @date 2021/12/14 21:24
  14. * =====================================================
  15. */
  16. @Slf4j
  17. @SpringBootApplication
  18. @EnableDiscoveryClient // 服务注册与发现
  19. public class GatewayApplication {
  20. public static void main(String[] args) {
  21. SpringApplication.run(GatewayApplication.class, args);
  22. }
  23. @Bean
  24. @Order(-1)
  25. public GlobalFilter gf1(){
  26. return (exchange, chain) -> {
  27. log.info("前执行1=================");
  28. return chain.filter(exchange).then(
  29. Mono.fromRunnable(() -> {
  30. log.info("后执行1=================");
  31. })
  32. );
  33. };
  34. }
  35. }

7、Gateway跨域问题

浏览器到网关:存在跨域

网关到其他服务:不存在跨域

springboot项目跨域解决方式:加注解@CrossOrigin

由于Gateway使用的是Webflux,而不是SpringMVC,所以需要先关闭SpringMVC的cors,再从Gateway的Filter里面设置cors

Gateway解决跨域

1、配置方式

  1. spring:
  2. cloud:
  3. # 网关配置
  4. gateway:
  5. # 跨域配置
  6. globalcors:
  7. cors-configurations:
  8. '[/**]':
  9. allowCredentials: true # 开启支持用户凭据
  10. allowedOrigins: "*" # 远程服务器
  11. allowedMethods: "*" # 请求方法
  12. allowedHeaders: "*" # 请求头

 2、编码方式

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.cors.CorsConfiguration;
  4. import org.springframework.web.cors.reactive.CorsWebFilter;
  5. import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
  6. /**
  7. * =====================================================
  8. * Gateway跨域配置
  9. * @author 汐小旅Shiory
  10. * @date 2021/12/15 23:22
  11. * =====================================================
  12. */
  13. @Configuration
  14. public class CorsConfig {
  15. /**
  16. * CorsFilter 是SpringMVC的cors
  17. * CorsWebFilter 是Webflux的cors
  18. * @return
  19. */
  20. @Bean
  21. public CorsWebFilter corsWebFilter(){
  22. // 跨域配置
  23. CorsConfiguration config = new CorsConfiguration();
  24. config.setAllowCredentials(true);// 开启支持用户凭据
  25. config.addAllowedOrigin("*");// 远程服务器
  26. config.addAllowedMethod("*");// 请求方法
  27. config.addAllowedHeader("*");// 请求头
  28. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  29. // 为指定路径注册跨域配置
  30. source.registerCorsConfiguration("/**",config);
  31. CorsWebFilter corsWebFilter = new CorsWebFilter(source);
  32. return corsWebFilter;
  33. }
  34. }

3、跨域测试前端代码 

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>跨域测试</title>
  6. <script src="https://unpkg.com/vue@next"></script>
  7. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  8. </head>
  9. <body>
  10. <div id="app">
  11. {{ info }}
  12. </div>
  13. <script>
  14. const app = {
  15. data() {
  16. return {
  17. info: '请求失败!!'
  18. }
  19. },
  20. mounted () {
  21. axios
  22. .get('http://192.168.2.102:9999/demo3/gatewayTest')
  23. .then(response => (this.info = response.data))
  24. .catch(function (error) { // 请求失败处理
  25. console.log(error);
  26. });
  27. }
  28. }
  29. Vue.createApp(app).mount('#app')
  30. </script>
  31. </body>
  32. </html>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/831013
推荐阅读
相关标签
  

闽ICP备14008679号