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

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

首先写一个拦截器:

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

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

我这里的操作是:

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

java 复制代码
@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的方法是基于线程上下文实现的

ini 复制代码
	public static RequestAttributes getRequestAttributes() {
		RequestAttributes attributes = requestAttributesHolder.get();
		if (attributes == null) {
			attributes = inheritableRequestAttributesHolder.get();
		}
		return attributes;
	}

ThreadLocal:

arduino 复制代码
	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

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

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

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

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

解决

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

更改feign配置

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

就可以成功获取了。

相关推荐
一只叫煤球的猫42 分钟前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9651 小时前
tcp/ip 中的多路复用
后端
bobz9651 小时前
tls ingress 简单记录
后端
你的人类朋友2 小时前
什么是OpenSSL
后端·安全·程序员
bobz9653 小时前
mcp 直接操作浏览器
后端
前端小张同学5 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook5 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康6 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在6 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net
文心快码BaiduComate6 小时前
文心快码入选2025服贸会“数智影响力”先锋案例
前端·后端·程序员