feign远程调用方法时,请求需要携带信息的问题

文章讲述了在使用Feign进行远程调用时,如何在SpringSecurity环境下添加身份信息到请求头,以及在遇到Hystrix或Sentinel线程隔离时的处理。最终作者选择使用Sentinel的信号量隔离策略解决请求头获取问题。
摘要由CSDN通过智能技术生成

最近在写一个业务,结合feign远程调用和spring security,再发送请求的时候需在请求头中加入身份信息。而另一个服务,需要这份身份信息,来获取id,不然就会报错,这里我用jwt存储身份信息。

首先写一个拦截器:

写一个拦截器,拦截下来feign的请求并添加所需要的信息。

由于这个拦截器是配置类,可以把他放置在公有的包里。

我这里的操作是:

拦截下来请求,并获取请求头,将请求头信息传入到feign的template中。

@Slf4j
@Configuration
public class FeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        //获取request对象
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if(requestAttributes != null){
            //获取request
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            //获取请求头
            String authorization = request.getHeader("Authorization");
            log.info("FeignInterceptor.apply authorization:{}",authorization);
            System.out.println("FeignInterceptor.apply authorization:{}"+authorization);
            //将请求头信息传递到feign中
            template.header("Authorization", authorization);
        }
    }
}

然后在对应的client里配置该类

报错:

正常来说,如果没有配置隔离策略,那么就可以正常对请求进行拦截了,但是如果feign结合了hystrix或者sentinel的线程隔离的话,那么就会获取不到。

源码剖析

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

这个方法,是从上下文中获取内容

getRequestAttributes的方法是基于线程上下文实现的

	public static RequestAttributes getRequestAttributes() {
		RequestAttributes attributes = requestAttributesHolder.get();
		if (attributes == null) {
			attributes = inheritableRequestAttributesHolder.get();
		}
		return attributes;
	}

ThreadLocal:

	private static final boolean jsfPresent =
			ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());

	private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
			new NamedThreadLocal<>("Request attributes");

	private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
			new NamedInheritableThreadLocal<>("Request context");

可以看出,他需要从本地线程中来获取。

对比一下hystrix和sentinel

SentinelHystrix
隔离策略信号量隔离(限制每个服务线程请求数)线程池隔离/信号量隔离(cpu性能降低)
熔断降级策略基于慢调用比例(耗时比较久的熔断)或异常比例基于失败比率
实时指标实现滑动窗口滑动窗口(基于 RxJava)
规则配置支持多种数据源支持多种数据源
扩展性多个扩展点插件的形式
基于注解的支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持
流量整形支持慢启动、匀速排队模式不支持
系统自适应保护支持不支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000  #熔断超时时间

整合spring security的时候,远程调用接口想发送请求头信息,线程隔离的策略配置的是线程隔离。

由于在进行远程调用的时候,服务收到hystrix保护,在去调用的时候会去分配一些线程让该服务去执行,然后决定是否进行降级。而分配的这些线程是隔离的,也就是说无法访问本地线程的东西,因此在获取本地线程的请求头内容时返回为空,所以我们这里改成信号量隔离。采用更好的sentinel,它默认采用的是信号量隔离

在远程调用的时候获取不到请求头内容

解决

由于综合来看sentinel更为优秀,所以这里不去更改hystrix了,直接改用sentinel

更改feign配置 

feign:
  sentinel:
    enabled: true
  # hystrix:
  #   enabled: true
  circuitbreaker:
    enabled: true
# hystrix:
#   command:
#     default:
#       execution:
#         isolation:
#           thread:
#             timeoutInMilliseconds: 1000000  #熔断超时时间

就可以成功获取了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值