最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud Feign轉(zhuǎn)發(fā)請(qǐng)求頭(防止session失效)的解決方案

 更新時(shí)間:2020年10月26日 14:22:24   作者:學(xué)圓惑邊  
這篇文章主要介紹了SpringCloud Feign轉(zhuǎn)發(fā)請(qǐng)求頭(防止session失效)的解決方案,本文給大家分享兩種解決方案供大家參考,感興趣的朋友跟隨小編一起看看吧

微服務(wù)開發(fā)中經(jīng)常有這樣的需求,公司自定義了通用的請(qǐng)求頭,需要在微服務(wù)的調(diào)用鏈中轉(zhuǎn)發(fā),比如在請(qǐng)求頭中加入了token,或者某個(gè)自定義的信息uniqueId,總之就是自定義的一個(gè)鍵值對(duì)的東東,A服務(wù)調(diào)用B服務(wù),B服務(wù)調(diào)用C服務(wù),這樣通用的東西如何讓他在一個(gè)調(diào)用鏈中不斷地傳遞下去呢?以A服務(wù)為例:

方案1

最傻的辦法,在程序中獲取,調(diào)用B的時(shí)候再轉(zhuǎn)發(fā),怎么獲取在Controller中國(guó)通過注解獲取,或者通過request對(duì)象獲取,這個(gè)不難,在請(qǐng)求B服務(wù)的時(shí)候,通過注解將值放進(jìn)去即可;簡(jiǎn)代碼如下:
獲?。?
@RequestMapping(value = "/api/test", method = RequestMethod.GET)
public String testFun(@RequestParam String name, @RequestHeader("uniqueId") String uniqueId) {
  if(uniqueId == null ){
     return "Must defined the uniqueId , it can not be null";
  }
  log.info(uniqueId, "begin testFun... ");
 return uniqueId;
}

然后A使用Feign調(diào)用B服務(wù)的時(shí)候,傳過去:

@FeignClient(value = "DEMO-SERVICE")
public interface CallClient {

  /**
 * 訪問DEMO-SERVICE服務(wù)的/api/test接口,通過注解將logId傳遞給下游服務(wù)
 */
 @RequestMapping(value = "/api/test", method = RequestMethod.GET)
  String callApiTest(@RequestParam(value = "name") String name, @RequestHeader(value = "uniqueId") String uniqueId);

}

方案弊端:毫無疑問,這方案不好,因?yàn)閷?duì)代碼有侵入,需要開發(fā)人員沒次手動(dòng)的獲取和添加,因此舍棄

方案2

服務(wù)通過請(qǐng)求攔截器,在請(qǐng)求從A發(fā)送到B之后,在攔截器內(nèi)將自己需要的東東加到請(qǐng)求頭:
import com.intellif.log.LoggerUtilI;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * 自定義的請(qǐng)求頭處理類,處理服務(wù)發(fā)送時(shí)的請(qǐng)求頭;
 * 將服務(wù)接收到的請(qǐng)求頭中的uniqueId和token字段取出來,并設(shè)置到新的請(qǐng)求頭里面去轉(zhuǎn)發(fā)給下游服務(wù)
 * 比如A服務(wù)收到一個(gè)請(qǐng)求,請(qǐng)求頭里面包含uniqueId和token字段,A處理時(shí)會(huì)使用Feign客戶端調(diào)用B服務(wù)
 * 那么uniqueId和token這兩個(gè)字段就會(huì)添加到請(qǐng)求頭中一并發(fā)給B服務(wù);
 *
 * @author mozping
 * @version 1.0
 * @date 2018/6/27 14:13
 * @see FeignHeadConfiguration
 * @since JDK1.8
 */
@Configuration
public class FeignHeadConfiguration {
  private final LoggerUtilI logger = LoggerUtilI.getLogger(this.getClass().getName());

  @Bean
  public RequestInterceptor requestInterceptor() {
    return requestTemplate -> {
      ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      if (attrs != null) {
        HttpServletRequest request = attrs.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
          while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = request.getHeader(name);
            /**
             * 遍歷請(qǐng)求頭里面的屬性字段,將logId和token添加到新的請(qǐng)求頭中轉(zhuǎn)發(fā)到下游服務(wù)
             * */
            if ("uniqueId".equalsIgnoreCase(name) || "token".equalsIgnoreCase(name)) {
              logger.debug("添加自定義請(qǐng)求頭key:" + name + ",value:" + value);
              requestTemplate.header(name, value);
            } else {
              logger.debug("FeignHeadConfiguration", "非自定義請(qǐng)求頭key:" + name + ",value:" + value + "不需要添加!");
            }
          }
        } else {
          logger.warn("FeignHeadConfiguration", "獲取請(qǐng)求頭失?。?);
        }
      }
    };
  }

}

網(wǎng)上很多關(guān)于這種方法的博文或者資料,大同小異,但是有一個(gè)問題,在開啟熔斷器之后,這里的attrs就是null,因?yàn)槿蹟嗥髂J(rèn)的隔離策略是thread,也就是線程隔離,實(shí)際上接收到的對(duì)象和這個(gè)在發(fā)送給B不是一個(gè)線程,怎么辦?有一個(gè)辦法,修改隔離策略hystrix.command.default.execution.isolation.strategy=SEMAPHORE,改為信號(hào)量的隔離模式,但是不推薦,因?yàn)閠hread是默認(rèn)的,而且要命的是信號(hào)量模式,熔斷器不生效,比如設(shè)置了熔斷時(shí)間hystrix.command.default.execution.isolation.semaphore.timeoutInMilliseconds=5000,五秒,如果B服務(wù)里面sleep了10秒,非得等到B執(zhí)行完畢再返回,因此這個(gè)方案也不可取;但是有什么辦法可以在默認(rèn)的Thread模式下讓攔截器拿到上游服務(wù)的請(qǐng)求頭?自定義策略:代碼如下:

import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
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.stereotype.Component;
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;

/**
 * 自定義Feign的隔離策略;
 * 在轉(zhuǎn)發(fā)Feign的請(qǐng)求頭的時(shí)候,如果開啟了Hystrix,Hystrix的默認(rèn)隔離策略是Thread(線程隔離策略),因此轉(zhuǎn)發(fā)攔截器內(nèi)是無法獲取到請(qǐng)求的請(qǐng)求頭信息的,可以修改默認(rèn)隔離策略為信號(hào)量模式:hystrix.command.default.execution.isolation.strategy=SEMAPHORE,這樣的話轉(zhuǎn)發(fā)線程和請(qǐng)求線程實(shí)際上是一個(gè)線程,這并不是最好的解決方法,信號(hào)量模式也不是官方最為推薦的隔離策略;另一個(gè)解決方法就是自定義Hystrix的隔離策略,思路是將現(xiàn)有的并發(fā)策略作為新并發(fā)策略的成員變量,在新并發(fā)策略中,返回現(xiàn)有并發(fā)策略的線程池、Queue;將策略加到Spring容器即可;
 *
 * @author mozping
 * @version 1.0
 * @date 2018/7/5 9:08
 * @see FeignHystrixConcurrencyStrategyIntellif
 * @since JDK1.8
 */
@Component
public class FeignHystrixConcurrencyStrategyIntellif extends HystrixConcurrencyStrategy {

  private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategyIntellif.class);
  private HystrixConcurrencyStrategy delegate;

  public FeignHystrixConcurrencyStrategyIntellif() {
    try {
      this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
      if (this.delegate instanceof FeignHystrixConcurrencyStrategyIntellif) {
        // 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 ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                      HystrixThreadPoolProperties threadPoolProperties) {
    return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
  }

  @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();
      }
    }
  }
}

然后使用默認(rèn)的熔斷器隔離策略,也可以在攔截器內(nèi)獲取到上游服務(wù)的請(qǐng)求頭信息了;
這里參考的博客,感謝這位大牛:https://blog.csdn.net/Crystalqy/article/details/79083857

到此這篇關(guān)于SpringCloud Feign轉(zhuǎn)發(fā)請(qǐng)求頭(防止session失效)的解決方案的文章就介紹到這了,更多相關(guān)SpringCloud Feign轉(zhuǎn)發(fā)請(qǐng)求頭內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入理解mybatis的ParamNameResolver

    深入理解mybatis的ParamNameResolver

    ParamNameResolver是 MyBatis 中的一個(gè)重要組件,它為 MyBatis 提供了一種方便的方式來獲取方法參數(shù)的名稱,本文主要介紹了深入理解mybatis的ParamNameResolver,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • Spring整合Mybatis的全過程

    Spring整合Mybatis的全過程

    這篇文章主要介紹了Spring整合Mybatis的全過程,包括spring配置文件書寫映射器接口的實(shí)例代碼,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-06-06
  • JDK動(dòng)態(tài)代理之ProxyGenerator生成代理類的字節(jié)碼文件解析

    JDK動(dòng)態(tài)代理之ProxyGenerator生成代理類的字節(jié)碼文件解析

    這篇文章主要為大家詳細(xì)介紹了JDK動(dòng)態(tài)代理之ProxyGenerator生成代理類的字節(jié)碼文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決)

    SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決)

    這篇文章主要介紹了SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 如何解決maven報(bào)錯(cuò):不知道這樣的主機(jī)問題

    如何解決maven報(bào)錯(cuò):不知道這樣的主機(jī)問題

    這篇文章主要介紹了如何解決maven報(bào)錯(cuò):不知道這樣的主機(jī)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • springboot]logback日志框架配置教程

    springboot]logback日志框架配置教程

    這篇文章主要介紹了springboot]logback日志框架配置,logback既可以通過application配置文件進(jìn)行日志的配置,又可以通過logback-spring.xml進(jìn)行日志的配置,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-04-04
  • Java匹配正則表達(dá)式匯總

    Java匹配正則表達(dá)式匯總

    java匹配字符串表達(dá)式在我們數(shù)據(jù)處理方面是及其重要的,現(xiàn)在就把我這幾天數(shù)據(jù)處理比較常用的向大家介紹一下,常規(guī)的一些匹配方式就不介紹了,我們來學(xué)習(xí)一些特殊的,感興趣的朋友跟隨小編一起看看吧
    2023-03-03
  • SpringBoot之跨域過濾器配置允許跨域訪問方式

    SpringBoot之跨域過濾器配置允許跨域訪問方式

    這篇文章主要介紹了SpringBoot之跨域過濾器配置允許跨域訪問方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • SpringMvc MultipartFile實(shí)現(xiàn)圖片文件上傳示例

    SpringMvc MultipartFile實(shí)現(xiàn)圖片文件上傳示例

    本篇文章主要介紹了SpringMvc MultipartFile實(shí)現(xiàn)圖片文件上傳示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • eclipse配置tomcat10的詳細(xì)步驟總結(jié)

    eclipse配置tomcat10的詳細(xì)步驟總結(jié)

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著eclipse配置tomcat10的詳細(xì)步驟展開,文中有非常詳細(xì)的介紹及圖文示例,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

邵武市| 眉山市| 喀喇| 吉首市| 广宁县| 抚远县| 陆丰市| 南阳市| 手游| 雷山县| 镇安县| 华亭县| 藁城市| 榆树市| 长海县| 嘉鱼县| 元阳县| 边坝县| 武功县| 合山市| 山阴县| 新丰县| 湄潭县| 阿合奇县| 汶上县| 乡城县| 嘉峪关市| 溧水县| 平安县| 旌德县| 南投市| 武汉市| 永春县| 从江县| 宿迁市| 双城市| 都江堰市| 论坛| 兖州市| 贺州市| 阳谷县|