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  #熔断超时时间

就可以成功获取了。

相关推荐
小蜗牛慢慢爬行24 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
wm10431 小时前
java web springboot
java·spring boot·后端
龙少95433 小时前
【深入理解@EnableCaching】
java·后端·spring
溟洵5 小时前
Linux下学【MySQL】表中插入和查询的进阶操作(配实操图和SQL语句通俗易懂)
linux·运维·数据库·后端·sql·mysql
SomeB1oody7 小时前
【Rust自学】6.1. 定义枚举
开发语言·后端·rust
SomeB1oody7 小时前
【Rust自学】5.3. struct的方法(Method)
开发语言·后端·rust
啦啦右一9 小时前
Spring Boot | (一)Spring开发环境构建
spring boot·后端·spring
森屿Serien9 小时前
Spring Boot常用注解
java·spring boot·后端
盛派网络小助手11 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
∝请叫*我简单先生11 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl