当前位置:   article > 正文

spring cloud alibaba 完整实现(四)gateway网关集成_springcloud alibaba 集成gateway

springcloud alibaba 集成gateway

        前面的内容就不过多的回顾了,可以翻阅一下前面的spring cloud alibaba 完整实现系列,本章我们需要在原有基础上加入gateway网关的使用,以及常见的断言及过滤器设置,至于网关是什么,为什么要使用本章也不会详解,可自行百度,我们暂时还是以搭建为主,文末有源码链接

1.新建一个项目,并加入启动类及yml文件

2.引入gateway的依赖(因为在父pom中引入了spring cloud的版本,所以此次不需要指定具体版本,版本问题可以参考第一篇,注意gateway是属于spring cloud 而不是alibaba

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-gateway</artifactId>
  4. </dependency>

3.现在可以直接启动gateway项目了

 报错了,当然下面错误也很明显,因为网关是不需要web环境的,所以不能依赖spring boot,前面我们在父pom中直接引入了spring boot的依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>

现在使用gateway就需要把这个依赖放到各个需要的子目录中,删除父pom中的依赖,如下图

 此时启动,完成,那么gateway集成就完成了,简单伐。歪歪歪?就没了?发现这个玩意集成了也没啥用处呀。不着急,我们一步步的来

现在我们来修改yml文件,刚才没有贴yml,我只是在yml中写了当前的端口,以及服务名

 

但是现在网关没办法使用,网关的作用是将客户端发送的请求进行转发到对应服务器,我现在有一个用户和日志模块,那他怎么知道要转发到那一台?

我们先来尝试将服务转发到用户模块(静态路由

  1. server:
  2. port: 8880 #自定义端口
  3. spring:
  4. application:
  5. name: api-gateway
  6. cloud:
  7. gateway:
  8. routes:
  9. - id: user-service #唯一标识,建议配合服务名
  10. uri: http://localhost:8881 #匹配后提供的路由地址
  11. predicates:
  12. - Path=/user/** #断言,路径相匹配的进行路由

如果是user/**所有请求,转发到8881下

这个就是网关的简单使用,但是这个会有问题,首先我们是把端口写死的,而且只能匹配user/路径,如果有其他的还得加,我还有日志服务,或者还有其他服务,这个配置不就越写越多了。。。看来生产用这种并不合理

 要在变动的服务中间找到对应的内容,最好的方式就是我们的nacos,服务注册了,我们只需要找到对应的注册服务,端口啥的都不用管了:

  1. cloud:
  2. gateway:
  3. routes:
  4. - id: user-service
  5. uri: lb://user-service #使用nacos本地负载均衡策略
  6. #断言规则
  7. predicates:
  8. - Path=/**
  9. nacos:
  10. discovery:
  11. server-addr: 127.0.0.1:8848 #本地nacos地址

重启再次访问,也能够搞定,通过nacos中注册的user-service服务名,也能转发到。那么log服务咋搞?现在我们也需要给log服务做一个路由转发,因为我现在是匹配得所有请求,如果后面我还有一个什么服务,两个都有一个userController而且两个路径都是user/怎么办呢?

所以我们的yml还不行

  1. server:
  2. port: 8880 #自定义端口
  3. spring:
  4. application:
  5. name: api-gateway
  6. # cloud:
  7. # gateway:
  8. # routes:
  9. # - id: user-service #唯一标识,建议配合服务名
  10. # uri: http://localhost:8881 #匹配后提供的路由地址
  11. # predicates:
  12. # - Path=/user/** #断言,路径相匹配的进行路由
  13. cloud:
  14. gateway:
  15. routes:
  16. - id: user-service
  17. uri: lb://user-service #使用nacos本地负载均衡策略
  18. #断言规则
  19. predicates:
  20. - Path=/user-service/**
  21. filters:
  22. - StripPrefix=1 #去除上层路径
  23. - id: log-service
  24. uri: lb://log-service #使用nacos本地负载均衡策略
  25. #断言规则
  26. predicates:
  27. - Path=/log-service/**
  28. filters:
  29. - StripPrefix=1
  30. nacos:
  31. discovery:
  32. server-addr: 127.0.0.1:8848 #本地nacos地址

那么两个服务各自转发到各自的服务上这样就可以解决刚才的问题,当然还可以直接开启注册中心路由功能,这样下面的id什么的都可以不用配置了,两种都可以,在实际使用时,上面这种还更多一点,毕竟相对灵活,断言规则及过滤器根好控制下面是自动注册中心的(根据需求自行选择):

  1. server:
  2. port: 8880 #自定义端口
  3. spring:
  4. application:
  5. name: api-gateway
  6. # cloud:
  7. # gateway:
  8. # routes:
  9. # - id: user-service #唯一标识,建议配合服务名
  10. # uri: http://localhost:8881 #匹配后提供的路由地址
  11. # predicates:
  12. # - Path=/user/** #断言,路径相匹配的进行路由
  13. cloud:
  14. gateway:
  15. discovery:
  16. locator:
  17. enabled: true #开启注册中心路由
  18. # routes:
  19. # - id: user-service
  20. # uri: lb://user-service #使用nacos本地负载均衡策略
  21. # #断言规则
  22. # predicates:
  23. # - Path=/user-service/**
  24. # filters:
  25. # - StripPrefix=1 #去除上层路径
  26. #
  27. # - id: log-service
  28. # uri: lb://log-service #使用nacos本地负载均衡策略
  29. # #断言规则
  30. # predicates:
  31. # - Path=/log-service/**
  32. # filters:
  33. # - StripPrefix=1
  34. nacos:
  35. discovery:
  36. server-addr: 127.0.0.1:8848 #本地nacos地址

至此,我们集成gateway就完成了,现在我们各个服务的请求都可以从网关进入进行分发。下面我们来看一下关于断言及过滤器

断言

        我们先要明白什么是断言,gateway中断言的作用

Predicate(断言, 谓词) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。

断言就是说: 在 什么条件下 才能进行路由转发 gateway有很多内置的断言工厂:

1. 基于请求时间的断言

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间之内

-After=2022-01-24T23:59:59.789+08:00[Asia/Shanghai]

2. ip地址断言

-RemoteAddr=192.168.1.1/24

3. cookie 断言

cookie是否具有给定名称且值与正则表达式匹配。

-Cookie=name, 正则

4. header 断言

是否具有给定名称且值与正则表达式匹配。

-Header=X-Request-Id, \d+

5. host 断言

主机名模式。判断请求的Host是否满足匹配规则。

-Host=**.baidu.com

6. Method 断言

-Method=GET

7. path 断言(上面我们就有使用这种断言方式)

PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。

-Path=/foo/{segment} 基于Query请求参数的断言工厂

QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具

有给定名称且值与正则表达式匹配。

-Query=name, 正则   

 8. 权重断言

接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发(同一服务多个配置才会使用)

-Weight= group1, 1

其实自带的断言工厂就够我们使用了,当然也可以自定义断言工厂我这儿写了两个自定义的断言工厂,代码其实是很简单,调试搞清楚数据就明白如何去调整自己想要的效果了

  1. package com.andy.gateway.route;
  2. import lombok.Data;
  3. import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.util.MultiValueMap;
  6. import org.springframework.web.server.ServerWebExchange;
  7. import java.util.Arrays;
  8. import java.util.List;
  9. import java.util.function.Predicate;
  10. /**
  11. * 自定义断言规则工厂
  12. * 实现步骤:
  13. * 1.创建java类,类名必须以RoutePredicateFactory结尾
  14. * 2.继承AbstractRoutePredicateFactory 类
  15. * 3.编写Config内部类,构建断言参数
  16. * 4.泛型调整为Config
  17. * 5.重写apply(断言规则逻辑代码) 及 shortcutFieldOrder(断言参数及顺序传入)
  18. * 6.构造方法调用super传入Config
  19. * 7.修改yml
  20. * #断言规则
  21. * predicates:
  22. * - name: Custom
  23. *
  24. * 这个代码没必要去记,我们还可以找到 AbstractRoutePredicateFactory 的实现类,随便找个复制一下,修改使用也可以
  25. */
  26. @Component
  27. public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
  28. public CustomRoutePredicateFactory(){
  29. super(Config.class);
  30. }
  31. @Override
  32. public Predicate<ServerWebExchange> apply(Config config) {
  33. return (exchange ->{
  34. MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
  35. int sex = Integer.parseInt(queryParams.getFirst("sex"));
  36. int age = Integer.parseInt(queryParams.getFirst("age"));
  37. //具体业务判断,false访问失败 true 继续
  38. if(sex == 0 && age>18 && age<28){
  39. System.out.println("美女请进");
  40. return true;
  41. }
  42. System.out.println(sex+"---"+config);
  43. return false;
  44. });
  45. }
  46. /**
  47. * 传入参数字段,及顺序
  48. * @return
  49. */
  50. @Override
  51. public List<String> shortcutFieldOrder() {
  52. //参数名称及顺序
  53. return Arrays.asList("sex","age");
  54. }
  55. @Data
  56. static class Config{
  57. private int sex;
  58. private int age;
  59. }
  60. }
  1. package com.andy.gateway.route;
  2. import lombok.Data;
  3. import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
  4. import org.springframework.http.HttpHeaders;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.web.server.ServerWebExchange;
  7. import java.util.Arrays;
  8. import java.util.List;
  9. import java.util.function.Predicate;
  10. /**
  11. * 自定义 Gateway 断言 Auth 后面必须为 RoutePredicateFactory
  12. */
  13. @Component
  14. public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config> {
  15. public static final String AUTHO_KEY = "name";
  16. public static final String AUTHO_VALUE = "value";
  17. public AuthRoutePredicateFactory() {
  18. super(Config.class);
  19. }
  20. /**
  21. * 表示配置填写的顺序,例如:- Auth=zhangsan,xxx, zhangsan 代表 AUTHO_KEY , xxx 代表 AUTHO_VALUE
  22. * @return
  23. */
  24. @Override
  25. public List<String> shortcutFieldOrder() {
  26. return Arrays.asList(AUTHO_KEY,AUTHO_VALUE);
  27. }
  28. @Override
  29. public Predicate<ServerWebExchange> apply(Config config) {
  30. // 如果 Header 中携带了某个值,进行 header 的判断
  31. return (exchange -> {
  32. // 获取请求 header
  33. HttpHeaders httpHeaders = exchange.getRequest().getHeaders();
  34. // 获取指定 header
  35. List<String> headerList = httpHeaders.get(config.getName());
  36. //header中是否包含zhangsan 参数,值为xxx
  37. // if(headerList.contains(config.value)){
  38. return true;
  39. // }
  40. // return false;
  41. });
  42. }
  43. /**
  44. * 获取的是yml里面的值
  45. */
  46. @Data
  47. public static class Config{
  48. private String name;
  49. private String value;
  50. }
  51. }

这上面是两个自定义断言,第一个实现的是请求参数必须带sex 和 age,然后必须是女,18-28才进行路由转发 。第二个是找请求头中必须包含 参数 zhangsan 而且值为xxx进行转发,yml的改动如下:

  1. predicates:
  2. - Path=/user-service/**
  3. - Auth=zhangsan,xxx
  4. # - name: Custom 启用Custom自定义断言

过滤器

         作用:过滤器就是在请求的传递过程中,对请求和响应做一些手脚

先看内置的(懒得去统计了,贴一个别人写的吧,需要使用的就对照一下):

Spring Cloud Gateway 内置的过滤器工厂_beishuibo1517的博客-CSDN博客本文基于Spring Cloud Greenwich SR2[TOC]内置的过滤器工厂这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格,虽然不是很详细,但能作为速览使用。如下:过滤器工厂作用参数AddRequestHeader为原始请求添加HeaderHeader的名称及值AddRequestParameter为原...https://blog.csdn.net/beishuibo1517/article/details/100963839下面还有一个官网的,自行选择吧:

Spring Cloud Gatewayicon-default.png?t=M0H8https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#gatewayfilter-factories

实现一个自定义的:

 

  1. package com.andy.gateway.filter;
  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.http.HttpStatus;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.server.ServerWebExchange;
  8. import reactor.core.publisher.Mono;
  9. /**
  10. * 自定义一个全局过滤器
  11. * 实现 globalfilter , ordered接口
  12. */
  13. @Component
  14. public class LoginFilter implements GlobalFilter, Ordered {
  15. /**
  16. * 执行过滤器中的业务逻辑
  17. * 对请求参数中的token进行判断
  18. * 如果存在此参数:代表已经认证成功
  19. * 如果不存在此参数 : 认证失败.
  20. * ServerWebExchange : 相当于请求和响应的上下文(zuul中的RequestContext)
  21. */
  22. @Override
  23. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  24. System.out.println("执行了自定义的全局过滤器");
  25. //1.获取请求参数token
  26. String token = exchange.getRequest().getQueryParams().getFirst("token");
  27. //2.判断是否存在
  28. // if(token == null) {
  29. // //3.如果不存在 : 认证失败
  30. // System.out.println("没有登录");
  31. // exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
  32. // return exchange.getResponse().setComplete(); //请求结束
  33. // }
  34. //4.如果存在,继续执行
  35. return chain.filter(exchange); //继续向下执行
  36. }
  37. /**
  38. * 指定过滤器的执行顺序 , 返回值越小,执行优先级越高
  39. */
  40. @Override
  41. public int getOrder() {
  42. return 0;
  43. }
  44. }

我把关键代码注释了,可以做参考,放开后是需要传入token就认为请求成功

其实断言和过滤器有点像,而且有些功能可以说两个都能实现。断言更像是门槛,过滤器则可以在请求中间做一些其他的事情

最后贴一下源码:

链接: https://pan.baidu.com/s/1rMR8OQvAHcNYYqOmnC1naA?pwd=id6h

提取码: id6h

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

闽ICP备14008679号