单体转微服务:正确的拆分思路与实战原则(下)

一.思路总结

前端发起请求到网关,由网关完成登录校验,并将用户id存入请求头中,然后在注册中心中获取微服务的信息,然后发送请求到微服务,其中拦截器拦截到该请求,获得用户信息并存入线程空间中,之后发送请求到微服务。服务返回结果给前端,然后释放线程空间。

那么问题来了?

token如何传递到前端?

不同微服务之间如何传递用户信息?

第一个问题:网关有断言,首先排除掉登录请求,然后请求发送到登录服务中。登录成功之后后端返回JWT给前端。

第二个问题:我们通过openfeign来实现微服务之间的远程调用。我们需要将用户信息存入请求头中。但是openfeign的请求发送是自动的,所以我们应该怎么办呢?oepenFeign为我们提供了RequestInterceptor拦截器。我们只要实现其中的方法,将用户id注入拦截器中即可。

本文重点探讨网关相关的操作

二.配置网关路由

1.引入依赖

复制代码
<!--common-->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>hm-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--nacos discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

2.编写启动类

复制代码
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

3.配置路由

复制代码
server:
  port: 8080
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848
    gateway:
      routes:
        - id: item # 路由规则id,自定义,唯一
          uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
          predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
            - Path=/items/**,/search/** # 这里是以请求路径作为判断规则
        - id: cart
          uri: lb://cart-service
          predicates:
            - Path=/carts/**
        - id: user
          uri: lb://user-service
          predicates:
            - Path=/users/**,/addresses/**
        - id: trade
          uri: lb://trade-service
          predicates:
            - Path=/orders/**
        - id: pay
          uri: lb://pay-service
          predicates:
            - Path=/pay-orders/**

三.网关登录校验

1.定义全局过滤器实现用户登录校验

复制代码
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    private final JwtTool jwtTool;
    private final AuthProperties authProperties;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求
        ServerHttpRequest request = exchange.getRequest();
        //判断是否放行
        RequestPath path = request.getPath();
        if(include( path)){
            return chain.filter(exchange);
        }
        //获取token
        String token = request.getHeaders().getFirst("Authorization");
        //校验并解析token
        String userId = null;
        try {
            //校验成功将用户信息存入请求头中,放行
            userId = jwtTool.parseToken(token).toString();

        } catch (Exception e) {
            //校验失败返回401
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        ServerWebExchange ex = exchange.mutate()
                .request(request.mutate().header("user", userId).build())
                .build();
        return chain.filter(ex);
    }

    private boolean include(RequestPath path) {
        if (authProperties.getExcludePaths().contains(path.toString())){
            return true;
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

2.重写RequestInterceptor实现微服务之间的用户id传递

复制代码
@Configuration
public class DefaultOprnfeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                //获取用户id
                Long userId = UserContext.getUser();
                if (userId == null){
                    return;
                }
                requestTemplate.header("authorization", "Bearer " + "123");
            }
        };
    }
}

四.配置管理

1.配置共享

<1>添加共享配置到Nacos

<2>添加依赖

复制代码
  <!--nacos配置管理-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <!--读取bootstrap文件-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
  </dependency>

<3>编写配置类

复制代码
hm:
  db:
    name: hm-item

<4>编写bookstrap拉取Nacos配置

2.配置热更新

<1>添加配置到Nacos

<2>写实体类接受参数

复制代码
Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {
    private Integer maxAmount;
}
相关推荐
Agent手记5 小时前
制造业生产流程自动化,Agent需要具备哪些能力?深度拆解2026工业级智能体落地范式与核心架构
大数据·人工智能·ai·架构·自动化
Yunzenn6 小时前
深度分析字节最新研究cola-DLM 第 07 章:推理流水线逐行拆解 —— 从 prompt 到生成文本
人工智能·驱动开发·深度学习·chatgpt·架构·prompt·github
颖火虫盟主7 小时前
Linux 系统分层架构:从硬件通电到 systemd 进程管理
linux·运维·架构
ฅ ฅBonnie8 小时前
Hermes 与 Cloud Code/OpenClaw 架构对比分析及部署实践
人工智能·ai·架构·ai编程
实在智能RPA9 小时前
实在Agent针对金融行业Agent灾备与高可用是如何进行设计的?深度拆解金融级智能体的架构安全与连续性保障
人工智能·安全·ai·金融·架构
用户1558319968149 小时前
文件同步冲突技术根因与解决方案:Last-Write-Wins、OT、CRDT对比
云原生
callJJ9 小时前
Nacos 详解——从概念到实战
java·spring boot·spring·spring cloud·微服务·nacos
zhangfeng11339 小时前
主流推理模型架构的协议对比表格,和专利坑 专利埋雷
人工智能·语言模型·自然语言处理·架构·开源·开源协议
这是谁的博客?9 小时前
LangChain 框架深度解析:从 LCEL 到 Agent 架构的核心原理
ai·架构·langchain·llm·agent·架构设计
Championship.23.249 小时前
Linux 3.0 中断机制深度解析:从传统PIC到现代中断架构的转折点
linux·运维·架构·中断