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

​

就可以成功获取了。

​

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
大勇前进4 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu4 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile4 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白804 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙4 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发4 天前
软件工程SOLID 五大设计原则
后端·软件工程