java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > 微服务feign添加token

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

作者:synda@hzy

这篇文章主要介绍了解决微服务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();
  }
}

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

您可能感兴趣的文章:
阅读全文