0


【SpringCloud】Gateway

一、网关路由

1.1.认识网关

网关就是络的口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由****和转发以及数据安全的校验。前端请求不能直接访问微服务,而是要请求网关:

  • 网关可以做安全控制,也就是登录身份校验,校验通过才放行
  • 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去

1.2.快速入门

1.2.1.引入依赖

  1. <!--网关-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--nacos discovery-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  10. </dependency>
  11. <!--负载均衡-->
  12. <dependency>
  13. <groupId>org.springframework.cloud</groupId>
  14. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  15. </dependency>

1.2.2.配置路由

  1. server:
  2. port: 8080
  3. spring:
  4. application:
  5. name: gateway
  6. cloud:
  7. nacos:
  8. server-addr: 192.168.150.101:8848
  9. gateway:
  10. routes:
  11. - id: item-service # 路由规则id,自定义,唯一
  12. uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
  13. predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
  14. - Path=/items/**,/search/** # 这里是以请求路径作为判断规则
  15. - id: cart-service
  16. uri: lb://cart-service
  17. predicates:
  18. - Path=/carts/**

id:建议和微服务名保持一致

uri:路由目标

lb:负载均衡 ://服务名称

predicates:路由断言

  • Path:以路径做匹配

二、网关登录校验

2.1.Gateway工作原理

  1. 客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(**Route**),然后将请求交给WebHandler去处理。
  2. WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain),然后按照顺序逐一执行过滤器(后面称为Filter)。
  3. 图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为prepost两部分,分别会在请求路由到微服务之前和之后被执行。
  4. 只有所有Filterpre逻辑都依次顺序执行通过后,请求才会被路由到微服务。
  5. 微服务返回结果后,再倒序执行Filterpost逻辑。
  6. 最终把响应结果返回。

2.2.自定义过滤器

网关过滤器链中的过滤器有两种:

  • **GatewayFilter**:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.
  • **GlobalFilter**:全局过滤器,作用范围是所有路由,不可配置。

2.3.登录校验

自定义GlobalFilter完成登录校验

自定义登录校验过滤器

  1. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  2. //1、获取请求头
  3. ServerHttpRequest request = exchange.getRequest();
  4. //2.判断是否不需要拦截
  5. if (isExclude(request.getPath().toString())) {
  6. return chain.filter(exchange);
  7. }
  8. //3.获取token
  9. List<String> headers = request.getHeaders().get("authorization");
  10. String token = null;
  11. if (headers != null && !headers.isEmpty()) {
  12. token = headers.get(0);
  13. }
  14. //4.解析校验token
  15. Long userId = null;
  16. try {
  17. userId = jwtTool.parseToken(token);
  18. } catch (UnauthorizedException e) {
  19. //拦截,设置响应状态码
  20. ServerHttpResponse response = exchange.getResponse();
  21. response.setRawStatusCode(401);
  22. return response.setComplete();
  23. }
  24. //System.out.println("userId = " + userId);
  25. //保存用户到请求头
  26. String userInfo = userId.toString();
  27. ServerWebExchange swe = exchange.mutate().//mutate 对下游请求做更改
  28. request(builder -> builder.header("user-info", userInfo))
  29. .build();
  30. //6.放行
  31. return chain.filter(swe);
  32. }

2.4.微服务获取用户

2.4.1.保存用户信息到请求头

  1. //保存用户到请求头
  2. String userInfo = userId.toString();
  3. ServerWebExchange swe = exchange.mutate().//mutate 对下游请求做更改
  4. request(builder -> builder.header("user-info", userInfo))
  5. .build();

2.4.2.拦截器获取用户

  1. /**
  2. * 拦截器,获取用户保存到ThreadLocal
  3. */
  4. public class UserInfoInterceptor implements HandlerInterceptor {
  5. //在controller执行之前运行
  6. @Override
  7. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  8. //1.获取用户信息
  9. String userInfo = request.getHeader("user-info");
  10. //2.将用户信息保存到ThreadLocal
  11. if (StrUtil.isNotBlank(userInfo)) {
  12. UserContext.setUser(Long.valueOf(userInfo));
  13. }
  14. //3.放行,只获取用户信息,不做拦截
  15. return true;
  16. }
  17. //清理用户
  18. @Override
  19. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  20. UserContext.removeUser();
  21. }
  22. }

配置拦截器

  1. @Configuration
  2. @ConditionalOnClass(DispatcherServlet.class)
  3. public class MvcConfig implements WebMvcConfigurer {
  4. @Override
  5. public void addInterceptors(InterceptorRegistry registry) {
  6. registry.addInterceptor(new UserInfoInterceptor());
  7. }
  8. }

不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是

  1. com.hmall.common.config

,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。

基于SpringBoot的自动装配原理,我们要将其添加到

  1. resources

目录下的

  1. META-INF/spring.factories

文件中:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.hmall.common.config.MyBatisConfig,\
  3. com.hmall.common.config.MvcConfig

2.5.OpenFeign传递用户

利用

  1. RequestTemplate

类来添加请求头,将用户信息保存到请求头中。这样以来,每次OpenFeign发起请求的时候都会调用该方法,传递用户信息。

  1. @Bean
  2. public RequestInterceptor UserInfoRequestInterceptor() {
  3. return requestTemplate -> {
  4. Long userId = UserContext.getUser();
  5. if (userId != null) {
  6. requestTemplate.header("user-info", userId.toString());
  7. }
  8. };
  9. }

三、配置管理

3.1.配置共享

我们可以把微服务共享的配置抽取到Nacos中统一管理,这样就不需要每个微服务都重复配置了。分为两步:

  • 在Nacos中添加共享配置
  • 微服务拉取配置

3.2.拉取配置共享

3.2.1.引入依赖

  1. <!--nacos配置管理-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  5. </dependency>
  6. <!--读取bootstrap文件-->
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  10. </dependency>

3.2.2.创建bootstrap.yaml

  1. spring:
  2. application:
  3. name: cart-service # 服务名称
  4. profiles:
  5. active: dev
  6. cloud:
  7. nacos:
  8. server-addr: 192.168.150.101 # nacos地址
  9. config:
  10. file-extension: yaml # 文件后缀名
  11. shared-configs: # 共享配置
  12. - dataId: shared-jdbc.yaml # 共享mybatis配置
  13. - dataId: shared-log.yaml # 共享日志配置
  14. - dataId: shared-swagger.yaml # 共享日志配置

3.3.配置热更新

3.3.1.添加配置到Nacos

dataId格式:

  1. [服务名]-[spring.active.profile].[后缀名]

文件名称由三部分组成:

  • **服务名**:购物车服务,所以是cart-service
  • **spring.active.profile**:就是spring boot中的spring.active.profile,可以省略,则所有profile共享该配置
  • **后缀名**:例如yaml

3.3.2.配置热更新

创建属性读取类

  1. @Data
  2. @Component
  3. @ConfigurationProperties(prefix = "hm.cart")
  4. public class CartProperties {
  5. private Integer maxAmount;
  6. }

3.4.动态路由

四、总结


本文转载自: https://blog.csdn.net/Etenal_/article/details/142025794
版权归原作者 柒末雪丶温存 所有, 如有侵权,请联系我们删除。

“【SpringCloud】Gateway”的评论:

还没有评论