微服务—Gateway

发布于:2025-08-06 ⋅ 阅读:(16) ⋅ 点赞:(0)

微服务—Gateway

参考项目路径: D:\Users\lenovo\Desktop\Java学习-代码集\Myself_Practice

网关:就是网络关口,负责请求的路由,转发、身份校验。

配置路由规则

spring:
	cloud:
		gateway:
		  routes:
		  	   — id: item                     # 路由规则id , 自定义 唯一 (最好和微服务名一致)
		  		uri: lb://item-service		 # 路由目标微服务,lb 代表负载均衡 
		  		predicates:  				# 路由断言,判断请求是否符合规则,符合规则到路由
		  			— Path=/items/**		# 以请求路径做判断,以 /items 开头 则符合规则 
		  	    — id: xx
		  		uri: lb://xx-service
		  		predicates:
		  			— Path=/xx/**,/XX/**,/xx/**
		  		
  • id:为每条路由规则设定的唯一标识符,建议和微服务名称保持一致。
  • uri:代表路由目标微服务,lb:// 表示使用负载均衡。
  • predicates:属于路由断言,借助特定条件来判定请求是否符合规则,符合的话就进行路由。
  • Path=/items/** 表示请求路径以 /items 开头的请求会被路由到 item-service 微服务。

依赖

        <!--  gateway  应用禁止引入spring-boot-starter-web 依赖,
             如果引入,当前应用无法启动!!!!!-->

		<!--geateway 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

		<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>

快速使用

一:新建一个模块,创建一个网关服务

二:新建一个 yaml 文件,配置 网关路由规则

示例:

spring:
  application:
    name: springcloud-alibaba-gateway
  cloud:
    gateway:
      routes:
        - id: springcloud-alibaba-consumer #设置id
          uri: lb://springcloud-alibaba-consumer  #设置服务名
          predicates:
            -  Method=GET,POST   #设置请求方法
            -  Path=/apia/**     #设置匹配路径的网关
          filters:
            - StripPrefix=1      #去掉前缀offer
        - id: springcloud-alibaba-feignconsumer
          uri: lb://springcloud-alibaba-feignconsumer
          predicates:
            - Method=GET,POST
            - Path=/apib/**
          filters:
            - StripPrefix=1
server:
  port: 8080

logging:
  level:
    org.springframework.cloud.gateway: debug

这时,我们通过8080 端口,通过路由匹配规则之后,就可以访问各个模块的接口 (注意,使用的是服务名发现,所以我们要在启动类上面加上 @EnableDiscoveryClient 这个注解)

路由属性

网关路由对应的 Java 类型 是 RouteDefinition, 其中常见的属性有:

  • id: 路由唯一标识
  • uri: 路由目标地址
  • predicates: 路由断言,判断请求是否符合当前路由
  • filters: 路由过滤器,对请求或响应做特殊处理

路由断言 predicates:

Spring 提供了 12种基本的 RoutePredicateFactory 实现

名称 说明 示例
After 是某个时间点后的请求 -After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before 是某个时间点之前的请求 -Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between 是某两个时间点之前的请求 -Between=2037-01-20T17:42:47.789-07:00[America/Denver],2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie 请求必须包含某些cookie -Cookie=chocolate,ch.p
Header 请求必须包含某些header - Header=X-Request-Id,\d+
Host 请求必须是访问某个host(域名) -Host=**.somehost.org,**.anotherhost.org
Method 请求方式必须是指定方式 - Method=GET,POST
Path 请求路径必须符合指定规则 -Path=/red/{segment),/blue/**
Query 请求参数必须包含指定参数 -Query=name,Jack或者-Query=name
RemoteAddr 请求者的ip必须是指定范围 -RemoteAddr=192.168.1.1/24
Weight 权重处理 -Weight=group1,2
XForwarded Remote Addr 基于请求的来源IP做判断 -XForwardedRemoteAddr=192.168.1.1/24

路由过滤器 filter :

参考 Spring Cloud Gateway 官方文档

网关登录校验

思路: 在 网关里面做 JWT 校验(转发之前),响应之后,将登录用户信息传给后面的服务。

网关请求处理流程:

大致流程: 网关拦截判断客户端发送的请求,然后,进行路由匹配,再转发到对应的微服务模块中去

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

零:引出问题:

  • 如何在网关转发之前做登录校验?
  • 网关如何将用户信息传递给微服务?
  • 如何在微服务之间传递用户信息?

所以我们要将 登录校验,放在 pre 阶段,也就是 过滤器之前。因此我们需要在网关内自定义一个过滤器,保证这个过滤器的执行顺序,在 NettyRoutingFilter 之前,并且还要保证在 pre 逻辑里,另外网关还需要将用户信息传递给各个微服务(保存用户到请求头)

一:自定义过滤器:

网关过滤器有两种,分别是:

  • GatewayFilter:路由过滤器,作用于任意指定得路由,默认不生效,要配置到路由后生效。
  • GlobalFilter:全局过滤器,作用氛围是所有路由;声明后自动生效。
public interface GlobalFilter {

    /**
     * ServerWebExchange: 请求上下文 包含整个过滤器链内共享数据,例如 request response等
     * GatewayFilterChain: 过滤器链 当前过滤器执行完之后,要调用过滤器链的下一个过滤器
     * @param exchange
     * @param chain
     * @return
     */
    Mono<Void>  filter(ServerWebExchange exchange, GatewayFilterChain chain);

}
自定义 GlobalFilter

示例:

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //模拟登录校验逻辑
        ServerHttpRequest request = exchange.getRequest(); //获取请求
        HttpHeaders headers = request.getHeaders();//获取请求头
        System.out.println("headers = " + headers);
        //放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //保证我们的过滤器在 NettyRoutingFilter 之前执行
        //实现Ordered 接口,返回值越小,优先级越高  NettyRoutingFilter的返回值最大所以我们return 0 就可以在它前面执行
        return 0;
    }
}

我们实现 GlobalFilter接口,声明这个类是全局拦截器,并通过 @Component 加到容器当中,然后,获取请求,进行一些登录校验的逻辑

我们还要确保这个自定义的全局拦截器要在 NettyRoutingFilter 拦截器之前运行,所以,实现 Ordered 接口,并返回0 数值越小,优先级越高。

自定义 GatewayFilter

自定义 GatewayFilter 不是直接实现 GatewayFilter , 而是继承 AbstractGatewayFilterFactory

spring:
  cloud:
    gateway:
      routes:
        - id: user_service                # 路由规则id , 自定义 唯一
          uri: lb://user-service          # 路由目标微服务,lb 代表负载均衡
          predicates:                     # 路由断言,判断请求是否符合规则,符合规则到路由
            - Path=/user/**               # 以请求路径做判断,以 /user 开头 则符合规则
        - id: post_service
          uri: lb://order-service
          predicates:
            - Path=/order/**,/shopping/**,/cart/**     # 以请求路径做判断,以 /order  , /shopping  , /cart 开头 则符合规则
      default-filters:  # 全局过滤器 拦截所有请求
        - printAny=小新,5,
@Component
public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> {

    @Override
    public GatewayFilter apply(Config config) {
        return new OrderedGatewayFilter( new GatewayFilter(){
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                String name = config.getName();
                System.out.println("name = " + name);
                //模拟登录校验逻辑
                ServerHttpRequest request = exchange.getRequest();//获取请求
                HttpHeaders headers = request.getHeaders();//获取请求头
                System.out.println("打印日志");
                //放行 让下一个过滤器执行
                return chain.filter(exchange);
            }
        }, 1);
    }

    // 自定义配置属性 , 成员变量名称很重要
    @Data
    public static class Config{
        private String name;
        private int age;
        private String sex;
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        //将 name age sex 顺序和配置文件保持一致
        List<String> list = new ArrayList<>();
        list.add("name");
        list.add("age");
        list.add("sex");
        return list;
    }

    // 构造器 将 config 字节码传递给父类, 父类负责帮我们读取 yaml 的配置
    public PrintAnyGatewayFilterFactory(){
        super(Config.class);
    }
}
  • 首先要注意的是,我们自定义的GatewayFilter的类名要是统一的后缀为 GatewayFilterFactory ,例如 PrintAnyGatewayFilterFactory

  • 这个是自定义了一个有参数的 GatewayFilter 拦截器 我们在 yaml 文件中 写参数。

  • 另外 我们的 GatewayFilter 工厂 new 的是 OrderedGatewayFilter 方便我们进行拦截器的先后拦截顺序。

  • 变量的顺序,就和我们在配置文件中的顺序是一致的。

二:实现登录校验:

需求:在网关中基于 过滤器 实现 登录校验 功能

@ConfigurationProperties 是 Spring Boot 框架中的一个注解,它主要用于将配置文件(如 application.propertiesapplication.yml)中的属性值绑定到 Java Bean 上,方便在代码中使用配置信息。

  • 示例:

  • hm:
       jwt:
           location: Haikou
           name: Xxx
           age: 16
    
  • @Data
    @Component
    @ConfigurationProperties(prefix="hm.jwt")
    public class JwtProperties{
        private String location;
        private String name;
        private int age;
    }
    
    • 必须为每个需要绑定的字段提供 setter 方法,因为 Spring Boot 通过调用 setter 方法来设置属性值。
    • 组件扫描:使用 @ConfigurationProperties 注解的类需要被 Spring 容器管理,可以使用 @Component 注解或在配置类中使用 @EnableConfigurationProperties 注解来启用。
自定义网关登录校验 过滤器:
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private AuthYaml authYaml;

    //将 JwtTool 工具类注入
    @Autowired
    private JwtTool jwtTool;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();// 路径匹配器 spring 内置的 路径匹配器

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1、获取 request
        ServerHttpRequest request = exchange.getRequest();
        //2、判断是否需要做登录拦截
        //判断请求路径,是否和我们在yaml文件中白名单配置的路径一致,如果一致就放行
        RequestPath path = request.getPath();
        //通过,我们自定义的 isTrue 方法判断是否需要做登录拦截
        if (this.isTrue(path.toString())) {
            //放行
            return chain.filter(exchange);
        }
        //下面是需要进行登录拦截校验的逻辑
        //3、获取token
        List<String> auth = request.getHeaders().get("authorization");
        String token = null;
        if (auth != null && !auth.isEmpty()){
            System.out.println("auth = " + auth);
            token = auth.get(0);
        }
        //4、校验并解析 token
        try {
            Long userId = jwtTool.parseToken(token);
            System.out.println("token = " + token);
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete(); // 拦截终止请求
        }
        //5、传递用户信息

        //6、放行 让下一个过滤器执行
        return chain.filter(exchange);
    }


    private boolean isTrue(String path) {
        // 判断是否需要做登录拦截
        //判断和我们在yaml文件中白名单配置的路径一致,如果一致就放行,返回true
        for (String excludePath : authYaml.getExcludePaths()) {
            if(antPathMatcher.match(excludePath, path)){
                // 匹配成功
                return true;
            }
        }
            return false;
    }


    // 优先级 值越小,优先级越高
    //保证我们的过滤器在 NettyRoutingFilter 之前执行
    @Override
    public int getOrder() {
        return 1;
    }
}
  • AuthYaml 相关

    xjh:
      jwt:
        location: HaiKou
        alias: xjh
        password: 123456
        tokenTTL: 30m
      auth:
        excludePaths:
          - /user/login
          - /user/register
    
    @Data
    @Component
    @ConfigurationProperties(prefix = "xjh.auth")
    public class AuthYaml {
        private List<String> excludePaths;
    }
    
  • JwtTool 相关

    @Component
    public class JwtTool {
    
        private final JWTSigner jwtSigner; //正版
    
    
        public JwtTool(KeyPair keyPair) {
            this.jwtSigner =  JWTSignerUtil.createSigner("HS256", keyPair);
        }
    
    
        public String createJwt(String userId, Duration ttl) {
            return JWT.create()
                    .setPayload("userId", userId)
                    .setExpiresAt(new Date(System.currentTimeMillis() + ttl.toMillis())) // 设置过期时间
                    .setSigner(jwtSigner)  //正版
                    .sign();
        }
    
    
        public Long parseToken(String token) {
            //1、校验token 是否为空
            if (token == null) {
                throw new UnauthorizedException("token 为空");
            }
            //2、校验并解析 jwt
            JWT jwt;
            try {
                jwt = JWT.of(token).setSigner(jwtSigner); //      正版
            } catch (Exception e) {
                throw new UnauthorizedException("token 解析失败");
            }
            //3、校验 token 是否有效
            if (!jwt.verify()) {
                throw new UnauthorizedException("token 无效");
            }
            //4、校验 token 是否过期
            try {
                JWTValidator.of(jwt).validateDate();
            } catch (ValidateException e) {
                throw new UnauthorizedException("token 过期");
            }
            //5、数据格式校验
            Object userId = jwt.getPayload("userId");
            if (userId == null) {
                throw new UnauthorizedException("token 无效");
            }
            //6、数据解析
            try {
                return Long.valueOf(userId.toString());
            } catch (NumberFormatException e) {
                throw new UnauthorizedException("token 无效");
            }
        }
    
    }
    
SecurityConfig 类相关

SecurityConfig 类的主要作用是为 Spring 应用程序配置与安全相关的 Bean。具体来说: 提供一个密码编码器 PasswordEncoder,用于在用户认证过程中对密码进行加密和验证,保护用户密码的安全性。 从密钥库中获取密钥对 KeyPair,这个密钥对通常用于 JWTJSON Web Token)的签名和验证,确保 JWT 的完整性和真实性,从而实现基于 JWT 的身份验证和授权机制。

@Configuration  // 专门定义配置类 该类可以包含多个 @Bean 注解的方法,这些方法会返回 Spring 容器要管理的 Bean 实例。
@EnableConfigurationProperties(JwtYaml.class)
public class SecurityConfig {  //生成密钥的配置类

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public KeyPair keyPair(JwtYaml jwtYaml){
        //获取密钥工厂
        KeyStoreKeyFactory keyStoreKeyFactory =
                new KeyStoreKeyFactory(
                        jwtYaml.getLocation(),
                        jwtYaml.getPassword().toCharArray());
        //获取密钥对
        return keyStoreKeyFactory.getKeyPair(
                jwtYaml.getAlias(),
                jwtYaml.getPassword().toCharArray()
        );
    }


}

JwtYaml 相关

xjh:
  jwt:
    location: HaiKou
    alias: xjh
    password: 123456
    tokenTTL: 30m
  auth:
    excludePaths:
      - /user/login
      - /user/register
@Data
@Component
@ConfigurationProperties(prefix = "xjh.jwt")
public class JwtYaml {
    private Resource location;
    private String alias;
    private String password;
    private Duration tokenTTL;
}

三:网关传递用户:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

思路,过滤器经过之后,我们将用户信息保存到请求头当中,然后加一层拦截器,从请求头中拿到信息将用户信息存储到 ThreadLocal 这样就可以不用每个微服务都去进行相关的处理。

3.1 在网关的登录校验过滤器中,把获取到的用户写入请求头

需求:修改 gateway 模块中的 登录校验拦截器,在校验成功之后,将用户 保存到下游请求的请求头当中去。

提示:要修改转发到微服务的请求,需要用到 ServerWebExchange 类下的 API

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private AuthYaml authYaml;

    //将 JwtTool 工具类注入
    @Autowired
    private JwtTool jwtTool;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();// 路径匹配器 spring 内置的 路径匹配器



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1、获取 request
        ServerHttpRequest request = exchange.getRequest();
        //2、判断是否需要做登录拦截
        //判断请求路径,是否和我们在yaml文件中白名单配置的路径一致,如果一致就放行
        RequestPath path = request.getPath();
        //通过,我们自定义的 isTrue 方法判断是否需要做登录拦截
        if (this.isTrue(path.toString())) {
            //放行
            return chain.filter(exchange);
        }
        //下面是需要进行登录拦截校验的逻辑
        //3、获取token
        List<String> auth = request.getHeaders().get("authorization");
        String token = null;
        if (auth != null && !auth.isEmpty()){
            System.out.println("auth = " + auth);
            token = auth.get(0);
        }
        //4、校验并解析 token
        Long userId;
        try {
            userId = jwtTool.parseToken(token);
            System.out.println("token = " + token);
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete(); // 拦截终止请求
        }
        //5、传递用户信息
        String userInfo = String.valueOf(userId);
        ServerWebExchange userExchange =  exchange.mutate() // 对下游的 request 进行修改 就是修改gateway之后的请求
                .request(builder -> builder.header("user-info", userInfo))
                .build();
        //6、放行 让下一个过滤器执行
        return chain.filter(userExchange);
    }


    private boolean isTrue(String path) {
        // 判断是否需要做登录拦截
        //判断和我们在yaml文件中白名单配置的路径一致,如果一致就放行,返回true
        for (String excludePath : authYaml.getExcludePaths()) {
            if(antPathMatcher.match(excludePath, path)){
                // 匹配成功
                return true;
            }
        }
            return false;
    }


    // 优先级 值越小,优先级越高
    //保证我们的过滤器在 NettyRoutingFilter 之前执行
    @Override
    public int getOrder() {
        return 1;
    }
}

对过滤器的第五、六步进行修改

        //5、传递用户信息
        String userInfo = String.valueOf(userId);
        ServerWebExchange userExchange =  exchange.mutate() // 对下游的 request 进行修改 就是修改gateway之后的请求
                .request(builder -> builder.header("user-info", userInfo))
                .build();
        //6、放行 让下一个过滤器执行
        return chain.filter(userExchange);
  • mutate() 就是对下游请求进行修改
  • header(param1 , param2) 里面的两个参数:第一个用户信息在请求头中的名字,第二个就是用户信息
  • 将 修改之后的 exchange 交到下一个过滤器进行执行
3.2 在common 模块 中编写 SpringMVC 拦截器,获取登录用户 !!!!(重要)

由于可能有多个模块需要获取到用户信息,我们直接在 common 层 定义拦截器,这样只要各微服务模块引用了 common 的依赖,就可以生效,无需重新编写。

//Spring MVC的拦截器还需要进行配置才可以
public class UserInfoInterceptor implements HandlerInterceptor {
    /**
     *大致思路:
     * 在请求到达Controller之前,获取用户信息,然后将用户信息存储到ThreadLocal中。
     * 在controller 后,将用户信息从ThreadLocal中移除,避免内存泄漏。
     * HandlerInterceptor 拦截器 会在 请求到达Controller之前执行,返回true表示继续执行,返回false表示请求终止。
     */

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1、获取登录用户信息
        String userInfo = request.getHeader("user-info");  //这里要和我们在过滤器中设置的一致!!!!!!
        //2、判断是否获取到了登录用户信息,有就存储到ThreadLocal中
        if (StrUtil.isNotBlank(userInfo)){
            //将用户信息存储到ThreadLocal中
            UserContext.setUserId(Long.valueOf(userInfo));
        }
        //3、放行
        return true;
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清理用户
        UserContext.clear();
    }


}
  • 写一个 UserContext 工具类,帮助我们进行 用户信息的 管理

    public class UserContext {
    
        private static final ThreadLocal<Long> userId = new ThreadLocal<>();
    
        public static void setUserId(Long id) {
            userId.set(id);
        }
    
        public static Long getUserId() {
            return userId.get();
        }
    
        public static void clear() {
            userId.remove();
        }
    
    }
    

此时,拦截器还不会生效,我们需要进行如下配置

SpringMVC 的拦截器 配置到 MVC当中,利用 addInterceptors 将我们自定义的拦截器添加到 MVC 的配置当中。

@Configuration
//只要是微服务,就有 SpringMVC 就会有DispatcherServlet
//因为网关没有SpringMVC,就没有 DispatcherServlet 所以这个配置在网关服务中就不会生效
@ConditionalOnClass(DispatcherServlet.class) // 仅在存在 DispatcherServlet 类时才加载配置
public class MvcConfig implements WebMvcConfigurer {
    //Spring MVC的拦截器还需要进行配置才可以

    @Override
    public void addInterceptors(InterceptorRegistry registry) {// 拦截器配置
        registry.addInterceptor(new UserInfoInterceptor())//添加 UserInfoInterceptor 拦截器
                .addPathPatterns("/**"); // 拦截所有请求
    }
}

然后在 rescourse 包下创建 META-INF 文件夹, 在文件夹中新建spring.factories 文件

# 这里将 MvcConfig 配置到 spring.factories 文件中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.common.config.MVCConfig.MvcConfig

此时,我们配置的 webconfig 就可以被扫描到 又因为,各个微服务模块都引用了common 模块,所以说,各个模块的MVC 都可以扫描到,但是,在 Spring Cloud Gateway 里,不存在传统意义上的 Spring MVC 框架,所以可能会扫描不到配置,所以,我们在 MvcConfig 中在配置的时候添加条件

@ConditionalOnClass(DispatcherServlet.class)// 仅在存在 `DispatcherServlet` 类时才加载配置

只要是微服务,就有 SpringMVC 就会有DispatcherServlet
因为网关没有SpringMVC,就没有 DispatcherServlet 所以这个配置在网关服务中就不会生效

四:OpenFeign 传递用户信息

**需求:**在微服务项目中,很多业务需要多个微服务共同合作完成,而这个过程中也需要传递 登陆用户信息

提示: OpenFeign 中提供了一个拦截器接口,所有由OpenFeign 发起的请求都会先调用拦截器处理请求。

问题: 使用 OpenFeign 调用远程接口时默认不会经过你为普通请求配置的拦截器(如 Spring MVC 中的 HandlerInterceptor

解决方法: 依靠OpenFeign 的拦截接口, RequestInterceptor 接口,其中提供了一些方法可以让我们修改请求头

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OpenFeign 在微服务之间互相远程调用接口,而所有的Feign的远程接口都是定义在api模块,所以我们应该将拦截接口也定义在 api模块当中。

这里主要是解决 微服务之间通过 OpenFeign 调用的时候,没有经过拦截器的情况,有下面这个配置之后,在远程接口执行之前就会将用户信息添加到请求头之中

public class FeignConfig {


    @Bean
    public RequestInterceptor userInfoRequestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                // 获取当前登录用户信息
                Long userId = UserContext.getUserId();
                if (userId != null) {
                    // 将用户信息添加到请求头中
                    template.header("user-info", String.valueOf(userId));
                }
            }
        };
    }

}

重要!!!!

想要上面的配置类生效,我们需要把这个配置类,加在 feign 微服务的启动类之上

@EnableFeignClients(defaultConfiguration =FeignConfig.class )

而所有的Feign的远程接口都是定义在api模块,所以我们应该将拦截接口也定义在 api模块当中。**

这里主要是解决 微服务之间通过 OpenFeign 调用的时候,没有经过拦截器的情况,有下面这个配置之后,在远程接口执行之前就会将用户信息添加到请求头之中

public class FeignConfig {


    @Bean
    public RequestInterceptor userInfoRequestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                // 获取当前登录用户信息
                Long userId = UserContext.getUserId();
                if (userId != null) {
                    // 将用户信息添加到请求头中
                    template.header("user-info", String.valueOf(userId));
                }
            }
        };
    }

}

重要!!!!

想要上面的配置类生效,我们需要把这个配置类,加在 feign 微服务的启动类之上

@EnableFeignClients(defaultConfiguration =FeignConfig.class )

网站公告

今日签到

点亮在社区的每一天
去签到