一.OpenFeign传递用户信息
前端发起的请求都会经过网关再到微服务,由于我们之前编写的过滤器和拦截器功能,微服务可以轻松获取登录用户信息。
但有些业务是比较复杂的,请求到达微服务后还需要调用其它多个微服务。比如下单业务,流程如下:

网关将用户信息传递到微服务后,交易服务在保存订单后要发起对购物车的清理,这时我们要知道清理哪个用户的购物车,因此需要用户信息,这时我们就要将用户信息从交易微服务传递到购物车微服务。这就要向购物车发起请求。
下单的过程中,需要调用商品服务扣减库存,调用购物车服务清理用户购物车。而清理购物车时必须知道当前登录的用户身份。但是,订单服务调用购物车时并没有传递用户信息,购物车服务无法知道当前用户是谁!
由于微服务获取用户信息是通过拦截器在请求头中读取,因此要想实现微服务之间的用户信息传递,就必须在微服务发起调用时把用户信息存入请求头。
微服务之间调用是基于OpenFeign来实现的,并不是我们自己发送的请求。我们如何才能让每一个由OpenFeign发起的请求自动携带登录用户信息呢?
这里要借助Feign中提供的一个拦截器接口:feign.RequestInterceptor

public interface RequestInterceptor {/*** Called for every request. * Add data using methods on the supplied {@link RequestTemplate}.*/void apply(RequestTemplate template);
}
我们只需要实现这个接口,然后实现apply方法,利用RequestTemplate
类来添加请求头,将用户信息保存到请求头中。这样以来,每次OpenFeign发起请求的时候都会调用该方法,传递用户信息。
二.接口实现
那么我们要将接口定义在哪里呢?很多微服务之间都要相互调用传递信息,因此我们定义在一个公共的地方。我们原来所有Feign的接口都是定义在hm-api中,因此放在这里最合适。我们之间在DefaultFeignConfig中定义该匿名内部类实现该接口。
package com.hmall.api.config;import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;// 定义一个OpenFeign配置类,用来配置OpenFeign的日志级别
public class DefaultFeignConfig {@Beanpublic Logger.Level feignLoggerLevel() {return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoInterceptor() {return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {Long userId = UserContext.getUser();if (userId != null) {requestTemplate.header("user-info", userId.toString());}}};}
}
我们要在hm-api中加入hm-common依赖,要不然UserContext使用不了。
为什么我们可以从UserContext中取出userId?因为请求进来先进行交易服务,进行交易服务时是从网关转过来的。这时请求头中是带用户信息的,所有交易服务可以拿到请求头用户信息并保存到UserContext中。而交易服务向购物车服务发起请求时该拦截器会生效,此时我们从UserContext中取一定能取到,取到的是交易服务中当前登录用户,然后把他保存到请求头,那么这个请求再转发到购物车服务时自然就会带上UserContext,那么购物车服务拦截器生效时也就能取出来了。
注意,我们要将该该配置类加入到加入到交易服务上,才能起作用。
TradeApplication.java:defaultConfiguration = DefaultFeignConfig.class
package com.hmall.trade;import com.hmall.api.config.DefaultFeignConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DefaultFeignConfig.class) // 启用Feign,且定义Feign的日志级别
@MapperScan("com.hmall.trade.mapper")
@SpringBootApplication
public class TradeApplication {public static void main(String[] args) {SpringApplication.run(TradeApplication.class, args);}
}
微服务登录解决方案总结
