当前位置:   article > 正文

SpringCloud GateWay与Nacos使用_springcloud gateway nacos

springcloud gateway nacos

网关就相当于一个内网与外网的出入口,起着 安全、验证的功能,如果没有网关,那么如果需要实现验证的功能,除非

SpringCloud GateWay 作为微服务的网关,起着如下作用

① 作为所有API接口服务请求的接入点

② 作为所有后端业务服务的聚合点,所有业务服务都可以在这里被调用

③ 实现安全、验证、路由、过滤、流控等策略,进行一些必要的中介处理

④ 统一管理: 提供配置管理工具,对所有API服务的调用生命周期和相应的中介策略进行统一的管理

(当然 由于多了一次中间转发,所以 QPS 就会下降)

下面就总结一下 SpringCloud GateWay 与 Nacos 的整合与使用

一、基础项目搭建

① 启动nacos 服务,这里是以单击的形式启动(nacos 下载地址可以自己百度)

  其默认端口为8848  账户名为nacos  密码为nacos 

 ② 创建项目

       父项目 (定义SpringCloud 版本 以及 SpringBoot 版本 以及公共 依赖)

       gateway-service (  子项目,实现Nacos 服务发现以及 权限过滤)

      user-service  (子项目,实现Nacos 服务注册以及充当服务提供者的功能)

   其结构图如下

父项目 pom.xml 文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.2</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>test_cloud_gateway</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>demo</name>
  15. <description>test_cloud_gateway</description>
  16. <modules>
  17. <module>gateway-service</module>
  18. <module>user-service</module>
  19. </modules>
  20. <properties>
  21. <java.version>8</java.version>
  22. <spring.boot.version>2.4.2</spring.boot.version>
  23. <alibaba.cloud.version>2021.1</alibaba.cloud.version>
  24. <spring.cloud.version>2020.0.1</spring.cloud.version>
  25. <jackson.verson>2.8.9</jackson.verson>
  26. <maven.compiler.source>1.8</maven.compiler.source>
  27. <maven.compiler.target>1.8</maven.compiler.target>
  28. </properties>
  29. <dependencies>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-test</artifactId>
  37. <scope>test</scope>
  38. </dependency>
  39. <!-- Nacos 配置管理 -->
  40. <dependency>
  41. <groupId>com.alibaba.cloud</groupId>
  42. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  43. </dependency>
  44. <!-- Nacos 服务发现 -->
  45. <dependency>
  46. <groupId>com.alibaba.cloud</groupId>
  47. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  48. </dependency>
  49. <!-- 使用log4j2 作为项目日志 -->
  50. <dependency>
  51. <groupId>org.springframework.boot</groupId>
  52. <artifactId>spring-boot-starter</artifactId>
  53. <exclusions> <!-- 去掉springboot自带的日志 -->
  54. <exclusion>
  55. <groupId>org.springframework.boot</groupId>
  56. <artifactId>spring-boot-starter-logging</artifactId>
  57. </exclusion>
  58. </exclusions>
  59. </dependency>
  60. <dependency>
  61. <groupId>org.springframework.boot</groupId>
  62. <artifactId>spring-boot-starter-log4j2</artifactId>
  63. </dependency>
  64. <!-- apache.commons begin -->
  65. <dependency>
  66. <groupId>org.apache.commons</groupId>
  67. <artifactId>commons-lang3</artifactId>
  68. </dependency>
  69. <!-- SpringCloud 框架 -->
  70. <dependency>
  71. <groupId>org.springframework.cloud</groupId>
  72. <artifactId>spring-cloud-starter</artifactId>
  73. </dependency>
  74. <dependency>
  75. <groupId>org.projectlombok</groupId>
  76. <artifactId>lombok</artifactId>
  77. <optional>true</optional>
  78. <version>1.18.20</version>
  79. </dependency>
  80. <dependency>
  81. <groupId>org.springframework.cloud</groupId>
  82. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  83. <version>3.1.1</version>
  84. </dependency>
  85. </dependencies>
  86. <dependencyManagement>
  87. <dependencies>
  88. <!-- spring cloud 依赖 -->
  89. <dependency>
  90. <groupId>org.springframework.cloud</groupId>
  91. <artifactId>spring-cloud-dependencies</artifactId>
  92. <version>${spring.cloud.version}</version>
  93. <type>pom</type>
  94. <scope>import</scope>
  95. </dependency>
  96. <dependency>
  97. <groupId>org.springframework.boot</groupId>
  98. <artifactId>spring-boot-dependencies</artifactId>
  99. <version>${spring.boot.version}</version>
  100. <type>pom</type>
  101. <scope>import</scope>
  102. </dependency>
  103. <dependency>
  104. <groupId>com.alibaba.cloud</groupId>
  105. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  106. <version>${alibaba.cloud.version}</version>
  107. <type>pom</type>
  108. <scope>import</scope>
  109. </dependency>
  110. </dependencies>
  111. </dependencyManagement>
  112. <build>
  113. <plugins>
  114. <plugin>
  115. <groupId>org.springframework.boot</groupId>
  116. <artifactId>spring-boot-maven-plugin</artifactId>
  117. <version>${spring.boot.version}</version>
  118. </plugin>
  119. </plugins>
  120. </build>
  121. </project>

( 吐槽一下:  SpringCloud 以及 SpringCloug Alibaba  的组件的版本之间有点坑,稍不注意就有可能导致 类缺少或者其他的问题)  

GateWay-service 服务

   pom.xml 文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>com.example</groupId>
  7. <artifactId>test_cloud_gateway</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>gateway-service</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>demo</name>
  15. <description>gateway-service</description>
  16. <properties>
  17. <java.version>17</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.cloud</groupId>
  22. <artifactId>spring-cloud-starter-gateway</artifactId>
  23. <version>3.0.4</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.cloud</groupId>
  27. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  28. <version>3.0.4</version> <!-- 版本号是必须要加的 -->
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-configuration-processor</artifactId>
  33. <optional>true</optional>
  34. </dependency>
  35. </dependencies>
  36. <build>
  37. <plugins>
  38. <plugin>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-maven-plugin</artifactId>
  41. </plugin>
  42. </plugins>
  43. </build>
  44. </project>

application.yml 文件

  1. spring:
  2. cloud:
  3. nacos:
  4. discovery:
  5. server-addr: 127.0.0.1:8848 # 注册中心地址
  6. username: nacos
  7. password: nacos
  8. locator:
  9. enabled: true # gateway 可以从nacos 中发现微服务
  10. application:
  11. name: gateway-service
  12. server:
  13. port: 9091

 (因为在bootstrap.yml文件中声明了配置中心以及文件的后缀格式,这时候项目启动就会自动获取nacos 上的gate-way-service.yaml 文件作为其启动配置项)

User-service 服务

   pom.xml 文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>com.example</groupId>
  7. <artifactId>test_cloud_gateway</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>user-service</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>user-service</name>
  15. <description>user-service</description>
  16. <properties>
  17. <java.version>8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-test</artifactId>
  27. <scope>test</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>com.fasterxml.jackson.core</groupId>
  31. <artifactId>jackson-databind</artifactId>
  32. <version>2.10.2</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-web</artifactId>
  37. <version>${spring.boot.version}</version>
  38. <exclusions> <!-- 去掉springboot自带的日志 -->
  39. <exclusion>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-starter-logging</artifactId>
  42. </exclusion>
  43. </exclusions>
  44. </dependency>
  45. </dependencies>
  46. <build>
  47. <plugins>
  48. <plugin>
  49. <groupId>org.springframework.boot</groupId>
  50. <artifactId>spring-boot-maven-plugin</artifactId>
  51. </plugin>
  52. </plugins>
  53. </build>
  54. </project>

application.yml

  1. server:
  2. port: 8099
  3. dubbo:
  4. application:
  5. name: ${spring.application.name}
  6. qos-enable: false
  7. registry:
  8. address: nacos://127.0.0.1:8848
  9. use-as-metadata-center: false
  10. use-as-config-center: false
  11. parameters:
  12. register-mode: instance

请求类:

  1. package com.example.userservice.controller;
  2. import com.example.userservice.pojo.User;
  3. import org.springframework.web.bind.annotation.PathVariable;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. /**
  9. * @author zhangyang
  10. * @version 1.0
  11. * @Date 2023/4/9 15:44
  12. * @Description
  13. */
  14. @RestController
  15. @RequestMapping("/user")
  16. public class UserController {
  17. private static Map<Integer, User> userMap;
  18. static {
  19. userMap = new HashMap<>();
  20. userMap.put(1, new User(1, "张三"));
  21. userMap.put(2, new User(2, "李四"));
  22. userMap.put(3, new User(3, "王五"));
  23. }
  24. @RequestMapping("/findById/{id}")
  25. public User findById(@PathVariable("id") Integer id) {
  26. // 为了测试方便,用此方式模拟用户查询
  27. return userMap.get(id);
  28. }
  29. }
  1. package com.example.userservice.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. /**
  5. * @author zhangyang
  6. * @version 1.0
  7. * @Date 2023/4/9 15:46
  8. * @Description
  9. */
  10. @AllArgsConstructor
  11. @Data
  12. public class User {
  13. private Integer id;
  14. private String name;
  15. }

③ 启动项目

 当我们启动项目后,就会在nacos 上看到注册的gateway-service 服务、user-service 服务

二、Springcloud Gateway  配置说明

  Gateway  本质上就是相当于 将请求封装成一个对象,然后去匹配设置的路由信息,

然后去通过filter 处理,然后调用微服务。

1、路由服务

  1. spring:
  2. cloud:
  3. nacos:
  4. discovery:
  5. server-addr: 127.0.0.1:8848 # 注册中心地址
  6. username: nacos
  7. password: nacos
  8. locator:
  9. enabled: true # gateway 可以从nacos 中发现微服务
  10. gateway:
  11. routes:
  12. - id: user-service-route # 路由的id,要保证其唯一性
  13. uri: lb://user-service # lb 表示 从nacos 中按照名称获取微服务,并遵循负载均衡策略, user-service 即微服务注册名
  14. predicates:
  15. - Path=/user-api/** # 使用断言
  16. filters:
  17. - StripPrefix=1 # 使用过滤器
  18. application:
  19. name: gateway-service
  20. server:
  21. port: 9091

        其中

   id:  路由标识符,用于区分其他route

   uri:    路由指向目的地uri,即客户端请求最终转发到微服务

  predicate:  断言,用于条件判断,只有断言都返回真,才会真正的执行路由  

  filter : 过滤器由于修改请求和响应信息

重新服务后,在地址栏上访问

 

 就会通过gateway 服务查询查询到对应的user-service 服务

全局过滤器

 全局过滤器作用域所有路由,无需配置,通过全局过滤器可以实现对权限的统一校验,安全性验证等功能

  1. package com.example.demo.filter;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import lombok.SneakyThrows;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  6. import org.springframework.cloud.gateway.filter.GlobalFilter;
  7. import org.springframework.core.Ordered;
  8. import org.springframework.core.io.buffer.DataBuffer;
  9. import org.springframework.http.HttpStatus;
  10. import org.springframework.http.server.reactive.ServerHttpResponse;
  11. import org.springframework.stereotype.Component;
  12. import org.springframework.web.server.ServerWebExchange;
  13. import reactor.core.publisher.Flux;
  14. import reactor.core.publisher.Mono;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. /**
  18. * @author zhangyang
  19. * @version 1.0
  20. * @Date 2023/4/10 10:53
  21. * @Description
  22. */
  23. @Component
  24. @Slf4j
  25. public class TokenGlobalFilter implements GlobalFilter, Ordered {
  26. @SneakyThrows
  27. @Override
  28. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  29. String token = exchange.getRequest().getQueryParams().getFirst("token");
  30. if (token == null || token.length() == 0 || !token.equals("123456")) {
  31. log.error("鉴权失败");
  32. ServerHttpResponse serverHttpResponse = exchange.getResponse();
  33. serverHttpResponse.setStatusCode(HttpStatus.OK);
  34. serverHttpResponse.getHeaders().add("Content-type", "application/json;charset=UTF-8");
  35. // 鉴权失败,返回的数据结构
  36. Map<String, Object> map = new HashMap<>();
  37. map.put("code", HttpStatus.UNAUTHORIZED.value());
  38. map.put("message", HttpStatus.UNAUTHORIZED.getReasonPhrase());
  39. DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(new ObjectMapper().writeValueAsBytes(map));
  40. return serverHttpResponse.writeWith(Flux.just(buffer));
  41. }
  42. return chain.filter(exchange);
  43. }
  44. @Override
  45. public int getOrder() {
  46. return 0;
  47. }
  48. }

这里是通过 网关的GlobalFilter 拦截请求头上的的token 字符串,然后用于获取token  如果不符合条件则直接异常信息

 

转发规则

  假设: uri 都设定为 http://localhost:9023****

规则实例说明
Path- Path=/gate/,/rule/ 当请求的路径为gate、rule开头的时,转发到http:9023服务器上
before- Before=2017-01-20T17:42:47.789-07:00[America/Denver]在某个时间之前的请求才会被转发到http://localhost:9023服务器上
After- After=2017-01-20T17:42:47.789-07:00[America/Denver]在某个时间之后请求才会被转发
Beteween- Between=2017-01-20T17:42:47.789-07:00[America/Denver],2017-01-21T17:42:47.789-07:00[America/Denver]在某个时间段之间的才会被转发
Cookie- Cookie=chocolate, ch.p名为chocolate的表单或者满足正则ch.p的表单才会被匹配到进行请求转发
Method- Method=GET只有GET方法才会匹配转发请求,还可以限定POST、PUT等请求方式

过滤器规则(Filter)

过滤器规则实例说明
PrefixPath- PrefixPath=/app在请求路径前加上app
RewritePath- RewritePath=/test, /app/test访问localhost:9092/test,请求会转发到localhost:8001/app/test
SetPathSetPath=/app/{path}通过模板设置路径,转发的规则时会在路径前增加app,{path} 表示原请求路径

 

路由失败处理

  当请求路由地址不匹配或者断言为false 的时候,GateWay 会默认返回Whitelabel ErrorPage 错误页面,这种错误提示不符合我们的业务需求。

我们可以自定义返回一个较为友好的错误提示,需要创建一个类继承DefaultErrorWebExceptionHandler 类,重写其方法

   

  1. public class MyErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
  2. public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes,
  3. ResourceProperties resourceProperties,
  4. ErrorProperties errorProperties,
  5. ApplicationContext applicationContext) {
  6. super(errorAttributes, resourceProperties, errorProperties, applicationContext);
  7. }
  8. @Override
  9. protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
  10. return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
  11. }
  12. @Override
  13. protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
  14. boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
  15. Map<String, Object> errorMap = getErrorAttributes(request, includeStackTrace);
  16. int status = Integer.valueOf(errorMap.get("status").toString());
  17. Map<String, Object> response = this.response(status, errorMap.get("error").toString(), errorMap);
  18. return ServerResponse.status(status).contentType(MediaType.APPLICATION_JSON)
  19. .body(BodyInserters.fromValue(response));
  20. }
  21. // 我们希望返回的数据结构
  22. public static Map<String, Object> response(int status, String errorMessage, Map<String, Object> errorMap) {
  23. Map<String, Object> map = new HashMap<>();
  24. map.put("code", status);
  25. map.put("message", errorMessage);
  26. map.put("data", errorMap);
  27. return map;
  28. }
  29. }

配置Bean 实例

  1. @Configuration
  2. public class GatewayConfiguration {
  3. private final ServerProperties serverProperties;
  4. private final ApplicationContext applicationContext;
  5. private final ResourceProperties resourceProperties;
  6. private final List<ViewResolver> viewResolvers;
  7. private final ServerCodecConfigurer serverCodecConfigurer;
  8. public GatewayConfiguration(ServerProperties serverProperties,
  9. ApplicationContext applicationContext,
  10. ResourceProperties resourceProperties,
  11. ObjectProvider<List<ViewResolver>> viewResolversProvider,
  12. ServerCodecConfigurer serverCodecConfigurer) {
  13. this.serverProperties = serverProperties;
  14. this.applicationContext = applicationContext;
  15. this.resourceProperties = resourceProperties;
  16. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
  17. this.serverCodecConfigurer = serverCodecConfigurer;
  18. }
  19. @Bean("myErrorWebExceptionHandler")
  20. @Order(Ordered.HIGHEST_PRECEDENCE)
  21. public ErrorWebExceptionHandler myErrorWebExceptionHandler(ErrorAttributes errorAttributes) {
  22. MyErrorWebExceptionHandler exceptionHandler = new MyErrorWebExceptionHandler(
  23. errorAttributes,
  24. this.resourceProperties,
  25. this.serverProperties.getError(),
  26. this.applicationContext);
  27. exceptionHandler.setViewResolvers(this.viewResolvers);
  28. exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
  29. exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
  30. return exceptionHandler;
  31. }
  32. }

重启Gateway项目后,访问一个不符合条件的断言

 

跨域访问

修改配置文件

  1. spring:
  2. cloud:
  3. nacos:
  4. discovery:
  5. server-addr: 127.0.0.1:8848 # 注册中心地址
  6. username: nacos
  7. password: nacos
  8. locator:
  9. enabled: true # gateway 可以从nacos 中发现微服务
  10. gateway:
  11. globalcors:
  12. cors-configurations:
  13. '[/**]':
  14. allowedOrigins: "*"
  15. allowedMethods: "*"
  16. alloedHeaders: "*"
  17. routes:
  18. - id: user-service-route # 路由的id,要保证其唯一性
  19. uri: lb://user-service # lb 表示 从nacos 中按照名称获取微服务,并遵循负载均衡策略, user-service 即微服务注册名
  20. predicates:
  21. - Path=/user-api/** # 使用断言
  22. filters:
  23. - StripPrefix=1 # 使用过滤器
  24. application:
  25. name: gateway-service
  26. server:
  27. port: 9091

整合Setinel 进行限流

 添加对应的依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.alibaba.csp</groupId>
  7. <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
  8. </dependency>
  9. 复制代码

修改对应的配置文件,连接Sentinel 控制台:

  1. spring:
  2. cloud:
  3. sentinel:
  4. transport:
  5. port: 8719
  6. dashboard: localhost:8081

配置对应的SentinelFilter 实例

  1. @Configuration
  2. public class GatewayConfiguration {
  3. @Bean
  4. @Order(-1)
  5. public GlobalFilter sentinelGatewayFilter() {
  6. return new SentinelGatewayFilter();
  7. }
  8. }

然后重启网关,登录Sentinel 控制台查看

 

 

        

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/57411
推荐阅读
相关标签
  

闽ICP备14008679号