解决微服务feign调用添加token的问题

微服务feign调用添加token

1.一般情况是这么配置的

具体的怎么调用就不说了 如下配置,就可以在请求头中添加需要的请求头信息。

package localdate;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
/**
 * feign调用服务时,会丢失请求头信息。需要在这里把认证信息收到添加上去
 * @author TRON
 * @since  2019-11-23
 *
 *
 */
@Configuration
@Slf4j
public class FeignTokenInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        log.info("======上下文中获取原请求信息======");
        String token = "without token";
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String HeadValue = request.getHeader(headerName);
            log.info("===原请求头信息=== headName: {}, headValue: {}", headerName, HeadValue);
            if (headerName.equals("X-Authorization-access_token")||headerName.equals("x-authorization-access_token")) {
                token = HeadValue;
            }
        }
        log.info("=======Feign添加头部信息start======");
//        requestTemplate.header("X-Authorization-access_token", token);
        requestTemplate.header("X-Authorization-access_token", "tron123456");
        log.info("=======Feign添加头部信息end======");
    }
}

2 .但是,当熔断开启后,原先的这么配置就不起作用了

package localdate;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 自定义并发策略
 * 将现有的并发策略作为新并发策略的成员变量
 * 在新并发策略中,返回现有并发策略的线程池、Queue
 *
 * hystrix.command.default.execution.isolation.strategy=THREAD
 * Hystrix的默认隔离策略(官方推荐,当使用该隔离策略时,是没办法拿到 ThreadLocal 中的值的,但是RequestContextHolder 源码中,使用了两个ThreadLocal)
 * hystrix.command.default.execution.isolation.strategy=SEMAPHORE (将隔离策略改为SEMAPHORE 也可以解决这个问题,但是官方并不推荐这个策略,因为这个策略对网络资源消耗比较大)
 *
 * 主要是解决当 Hystrix的默认隔离策略是THREAD时,不能通过RequestContextHolder获取到request对象的问题
 *
 */
//@Configuration
public class FeignConfig extends HystrixConcurrencyStrategy {
    private static final Logger log = LoggerFactory.getLogger(FeignConfig.class);
    private HystrixConcurrencyStrategy delegate;
    public FeignConfig() {
        try {
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof FeignConfig) {
                // Welcome to singleton hell...
                return;
            }
            HystrixCommandExecutionHook commandExecutionHook =
                    HystrixPlugins.getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
            HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy =
                    HystrixPlugins.getInstance().getPropertiesStrategy();
            this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
            HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        } catch (Exception e) {
            log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
        }
    }
    private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
                                                 HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) {
        if (log.isDebugEnabled()) {
            log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
                    + this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
                    + metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
            log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
        }
    }
    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return new WrappedCallable<>(callable, requestAttributes);
    }
    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize,
                                            HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
                unit, workQueue);
    }
    @Override
    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return this.delegate.getBlockingQueue(maxQueueSize);
    }
    @Override
    public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
        return this.delegate.getRequestVariable(rv);
    }
    static class WrappedCallable<T> implements Callable<T> {
        private final Callable<T> target;
        private final RequestAttributes requestAttributes;
        public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
            this.target = target;
            this.requestAttributes = requestAttributes;
        }
        @Override
        public T call() throws Exception {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                return target.call();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }
    }
}

3 .feign和熔断的配置

feign:
  client:
    config:
      default:
        connectTimeout: 5000   #连接超时3秒,连接失败时直接调用降级方法
        readTimeout: 100000     #连接成功,处理数据的时间限制10秒 100000   读取时间过短会抛异常java.net.SocketTimeoutException: Read timed out
        loggerLevel: full      #日志输出等级
  hystrix:
    enabled: true
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000  #服务连接成功,但是时间过长,降级方法调用时间   60000   5000

feign微服务的相互调用

我只是记录服务提供方、消费方的代码编写,配置什么的大家在网上搜,一大堆。

首先是服务提供方:

启动类上加上注解@EnableFeignClients,然后正常的写controller、service等业务逻辑

其次是服务的调用方:

1.首先启动类上加上注解@EnableFeignClients

2.编写服务调用接口

3.编写接口熔断处理方法

4.本人遇到的问题是需要用到调用方的请求头里面的信息,但是在提供方取不到,这时可以通过在调用方增加配置来解决

import feign.RequestInterceptor;
import feign.RequestTemplate;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author ydf
 * @date 2021/5/13
 * @description:
 **/
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {

  @Override
  public void apply(RequestTemplate requestTemplate) {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    Enumeration<String> headerNames = request.getHeaderNames();
    if (headerNames != null) {
      while (headerNames.hasMoreElements()) {
        String name = headerNames.nextElement();
        String values = request.getHeader(name);
        requestTemplate.header(name, values);
      }
    }
  }
}

import com.jingling.netsign.applet.interceptor.FeignBasicAuthRequestInterceptor;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author ydf
 * @date 2021/5/13
 * @description:
 **/
@Configuration
public class FeignSupportConfig {
  /**
   * feign请求拦截器
   *
   * @return
   */
  @Bean
  public RequestInterceptor requestInterceptor(){
    return new FeignBasicAuthRequestInterceptor();
  }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Feign调用服务各种坑的处理方案

    1.编写被调用服务 @RefreshScope @RestController public class XXXController extends BaseController implements IndicatorsFeignApi{ @Resource private XXXService xxx; @Override public Wrapper<CommonVo> getXXXX(@RequestBody CommonDto commonDto) { try { CommonVo

  • SpringCloud Feign服务调用请求方式总结

    前言 最近做微服务架构的项目,在用feign来进行服务间的调用.在互调的过程中,难免出现问题,根据错误总结了一下,主要是请求方式的错误和接参数的错误造成的.在此进行一下总结记录.以下通过分为三种情况说明,无参数,单参数,多参数.每种情况再分get和post两种请求方式进行说明.这样的话,6种情况涵盖了feign调用的所有情况. 有个建议就是为了保证不必要的麻烦,在写feign接口的时候,与我们的映射方法保持绝对一致,同时请求方式,请求参数注解也都不偷懒的写上.如果遵循这种规范,可以避开90%的调

  • SpringCloud feign微服务调用之间的异常处理方式

    如何优雅地处理微服务间调用的异常 现在微服务架构盛行,其中spring cloud方案就很具有代表. 那么在微服务之间进行调用,如果被调用的服务挂了,调用方如何感知呢? 一.加上hystrix熔断 在定义feignClient的地方指定熔断,如下图 当被调用服务不可用或者被调用方发生错误的时候,会触发熔断,但是,如果被调用方抛出异常,调用方怎么知道究竟是出了什么问题呢? 那,这就出现了 二.feign全局异常处理 我们不得不提到feign提供的一个接口叫做ErrorDecoder, 是用来处理f

  • 使用feign服务调用添加Header参数

    feign添加Header参数 @Configuration public class FeignConfiguration implements RequestInterceptor { private static final Logger logger = LoggerFactory.getLogger(FeignConfiguration.class); @Override public void apply(RequestTemplate template) { ServletRequ

  • Spring Cloud Feign统一设置验证token实现方法解析

    我们也在zuul中通过前置过滤器来统一设置token, 其实还漏掉了一种,那就是业务服务调用业务服务的时候,是没有zuul这种前置过滤器的,那么我们该如何设置呢? 其实也挺简单的,因为我们服务之前的调用是依赖于Feign的,我们可以从Feign上来做文章. 如果你仔细看过Feign的文档的话,肯定会注意到下面一段代码: static class DynamicAuthTokenTarget<T> implements Target<T> { public DynamicAuthTo

  • 解决微服务feign调用添加token的问题

    微服务feign调用添加token 1.一般情况是这么配置的 具体的怎么调用就不说了 如下配置,就可以在请求头中添加需要的请求头信息. package localdate; import feign.RequestInterceptor; import feign.RequestTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; imp

  • 解决微服务中关于用户token处理到的坑

    目录 关于用户token处理到的坑 目前常用的有以下几种方案: 微服务服务间调用传递token 代码如下 RequestInterceptor是feign提供的接口 关于用户token处理到的坑 当采用前后台完全分离,以微服务架构的搭建时.在搭建微服务过程中,由于每个服务都是独立的应用,这样就会造成一个统一用户的问题. 当用户从这个用户管理系统中登录后,在其他系统的如何判断用户是否已经登录的问题. 目前常用的有以下几种方案: 1.session .redis共享处理 2.Header存储toke

  • Feign如何解决服务之间调用传递token

    目录 解决服务之间调用传递token Feign有提供一个接口RequestInterceptor 调用方式 Feign调用服务各种坑处理 编写被调用服务 编写调用api 编写客户端服务 解决服务之间调用传递token 现在的微服务基本就是SpringSecurity+Oauth2做的授权和认证,假如多个服务直接要通过Fegin来调用,会报错401 a.有做权限处理的服务接口直接调用会造成调用时出现http 401未授权的错误,继而导致最终服务的http 500内部服务器错误 b.解决方式:最方

  • springcloud 如何解决微服务之间token传递问题

    目录 微服务之间token传递问题 服务A中FeginInterceptor 服务A添加配置文件 微服务服务间调用传递token RequestInterceptor是feign提供的接口 微服务之间token传递问题 假设现在有A服务,B服务,外部使用RESTApi请求调用A服务,在请求头上有token字段,A服务使用完后,B服务也要使用,如何才能把token也转发到B服务呢? 这里可以使用Feign的RequestInterceptor,但是直接使用一般情况下HttpServletReque

  • 分布式医疗挂号系统Nacos微服务Feign远程调用数据字典

    目录 步骤1:向Nacos服务中心注册微服务 (1)引入Nacos依赖 步骤2:使用Feign进行远程调用 (1)service-hosp医院列表接口 (2)service-cmn医院等级/地址接口 (3)引入Feign依赖 (4)调用端通过包扫描Feign (5)远程调用 步骤3:使用swagger测试 需求:制作一个医院列表的显示功能.列表中包含医院编号.医院等级.医院地址.状态等.分析:首先确定是典型的条件查询带分页.由于医院的等级需要查询数据字典部分,这个调用是在不同的微服务模块中,这就

  • Java Feign微服务接口调用方法详细讲解

    目录 Feign说明 引入依赖启动类开启客户端 Feign接口开发 编写容错类 在业务层调用Feign客户端接口 Feign的常用属性如下 Feign说明 Feign是一种声明式.模板化的HTTP客户端.在spring cloud中使用Feign,可以做到类似于普通的接口的请求调用,可以发现对应的服务的接口,进而直接调用对应服务中的接口. 引入依赖启动类开启客户端 首先需要引入依赖 <dependency> <groupId>org.springframework.cloud<

  • 教你Spring Cloud保证各个微服务之间调用安全性

    导读:在微服务的架构下,系统会根据业务拆分为多个服务,各自负责单一的职责,在这样的架构下,我们需要确保各api的安全性,也就是说服务不是开放的,而是需要授权才可访问的,避免接口被不合法的请求所访问. 但是在在微服务集群中服务之间暴力的接口,或者对于第三方开放的接口如果不做及安全和认证,后果可想而知. 阅读下文之前思考几个问题: 如何在restTemplate远程调用请求增加添加统一认证? 服务认证如何规范加密和解密? 远程调用统一什么协议比较合适? 如下图,三个服务注册到同一个注册中心集群,服务

  • 微服务间调用Retrofit在Spring Cloud Alibaba中的使用

    目录 前置知识 搭建 使用 集成与配置 服务间调用 服务限流 熔断降级 总结 前置知识 在微服务项目中,如果我们想实现服务间调用,一般会选择Feign.之前介绍过一款HTTP客户端工具Retrofit,配合SpringBoot非常好用!其实Retrofit不仅支持普通的HTTP调用,还能支持微服务间的调用,负载均衡和熔断限流都能实现.今天我们来介绍下Retrofit在Spring Cloud Alibaba下的使用,希望对大家有所帮助! SpringBoot实战电商项目mall(50k+star

  • Spring Cloud多个微服务之间调用代码实例

    这篇文章主要介绍了Spring Cloud多个微服务之间调用代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 现在又一个学生微服务 user 和 学校微服务 school,如果user需要访问school,我们应该怎么做? 1.使用RestTemplate方式 添加config import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.spr

随机推荐