1. 程式人生 > >Feign 呼叫丟失Header的解決方案

Feign 呼叫丟失Header的解決方案

問題

在 Spring Cloud 中 微服務之間的呼叫會用到Feign,但是在預設情況下,Feign 呼叫遠端服務存在Header請求頭丟失問題。

解決方案

首先需要寫一個 Feign請求攔截器,通過實現RequestInterceptor介面,完成對所有的Feign請求,傳遞請求頭和請求引數。

Feign 請求攔截器

public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(FeignBasicAuthRequestInterceptor.class);

    @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);
            }
        }
        Enumeration<String> bodyNames = request.getParameterNames();
        StringBuffer body =new StringBuffer();
        if (bodyNames != null) {
            while (bodyNames.hasMoreElements()) {
                String name = bodyNames.nextElement();
                String values = request.getParameter(name);
                body.append(name).append("=").append(values).append("&");
            }
        }
        if(body.length()!=0) {
            body.deleteCharAt(body.length()-1);
            requestTemplate.body(body.toString());
            logger.info("feign interceptor body:{}",body.toString());
        }
    }
}

通過配置檔案配置 讓 所有 FeignClient,來使用 FeignBasicAuthRequestInterceptor

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
        requestInterceptors: com.leparts.config.FeignBasicAuthRequestInterceptor

也可以配置讓 某個 FeignClient 來使用這個 FeignBasicAuthRequestInterceptor

feign:
  client:
    config:
      xxxx: # 遠端服務名
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
        requestInterceptors: com.leparts.config.FeignBasicAuthRequestInterceptor

經過測試,上面的解決方案可以正常的使用;但是出現了新的問題。

在轉發Feign的請求頭的時候, 如果開啟了Hystrix, Hystrix的預設隔離策略是Thread(執行緒隔離策略), 因此轉發攔截器內是無法獲取到請求的請求頭資訊的。

可以修改預設隔離策略為訊號量模式:

hystrix.command.default.execution.isolation.strategy=SEMAPHORE

但訊號量模式不是官方推薦的隔離策略;另一個解決方法就是自定義Hystrix的隔離策略。

自定義策略

HystrixConcurrencyStrategy 是提供給開發者去自定義hystrix內部執行緒池及其佇列,還提供了包裝callable的方法,以及傳遞上下文變數的方法。所以可以繼承了HystrixConcurrencyStrategy,用來實現了自己的併發策略。

@Component
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

    private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class);

    private HystrixConcurrencyStrategy delegate;

    public FeignHystrixConcurrencyStrategy() {
        try {
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {
                // 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 instance = HystrixPlugins.getInstance();
            instance.registerConcurrencyStrategy(this);
            instance.registerCommandExecutionHook(commandExecutionHook);
            instance.registerEventNotifier(eventNotifier);
            instance.registerMetricsPublisher(metricsPublisher);
            instance.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;

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

致此,Feign呼叫丟失請求頭的問題就解決的了 。

參考

https://blog.csdn.net/zl1zl2zl3/article/details/79084368
https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.0.RC2/reference/html/




歡迎掃碼或微信搜尋公眾號《程式設計師果果》關注我,關注有驚喜~

相關推薦

Feign 呼叫丟失Header解決方案

問題 在 Spring Cloud 中 微服務之間的呼叫會用到Feign,但是在預設情況下,Feign 呼叫遠端服務存在Header請求頭丟失問題。 解決方案 首先需要寫一個 Feign請求攔截器,通過實現RequestInterceptor介面,完成對所有的Feign請求,傳遞請求頭和請求引數。 Feign

VMware虛擬機 VC裏報告虛擬磁盤丟失解決方案

光纖 數據恢復 虛擬機中石化某省分公司的信息管理平臺,幾臺VMware虛擬機——ESX SERVER共享一臺IBM DS4100存儲,大約有40~50組虛擬機,占用1.8TB空間,正常工作中,vc裏報告虛擬磁盤丟失,ssh到ESX中執行fdisk -l查看磁盤,發現storage已經沒有分區表了。重啟所有設備

Long型別轉json時前端js丟失精度解決方案

一、問題背景 Java後端開發過程中,尤其是id欄位,因數值太大,通過json形式傳輸到前端後,在js解析時,會丟失精度。 如果對精度丟失沒有什麼概念,可以看一個知乎的帖子,來感受一下:https://www.zhihu.com/question/34564427?sort=created

Android Activity的onStop()與onDestroy() 回撥緩慢,延時呼叫的問題解決方案

前段時間做專案時遇到奇葩問題,特此記錄: 問題發現: 我們的專案在語句翻譯功能裡用到了百度語音識別和語音合成,把相關程式碼封裝到了library裡面,把library庫放到專案A裡面執行正常,同樣的庫移植到專案B裡面,居然有問題!!! 具體問題就是第一次進入Activity時正常,但是當退出

redis 叢集 資料丟失解決方案 AOF RDB 資料恢復

參考資料: Redis Persistence http://redis.io/topics/persistence Google Groups https://groups.google.com/forum/?fromgroups=#!forum/redis-db 一、對Redis持久化的探討與理解

openfire因為網路不穩定而造成訊息丟失解決方案

       1               2 C1 ------- S ------- C2 訊息丟失 狀態:C1線上,但C2因為網路問題,或是程序被殺死,並且此時伺服器還沒及時傳送ping 進行判斷C2是否線上。 第一種情況: 此時,當C1向C2傳送訊息時,步驟1可

Ubuntu 中/etc/resolv.conf 檔案修改丟失解決方案

使用wget下載檔案時出現unable to resolve host name http://xxxx,根據網上的方法修改了/etc/resolv.conf後問題解決,可是每次重啟電腦或者重啟network-manager後該檔案的修改總是丟失了 到底是誰改寫了這個檔案?

ASP.NET Session丟失問題解決方案總結及判斷Session是否過期【轉載】

判斷Session是否過期: 通過BasrPage或IHtttpMoudle實現public class BasePage : System.Web.UI.Page    {      public  BasePage()      {       }       prot

安裝rpm軟體,丟失解決方案

1/問題 [[email protected] ~]# rpm -ivh libevent-1.4.13-4.el6.i686.rpm error: Failed dependencies:libc.so.6 is needed by libevent-1.4.1

selenium 無法呼叫chrome driver 解決方案

下載適合的版本,並且eclipse中匯入selenium的jar包後,啟動chrome driver報錯,unknown error: Runtime.executionContextCreated has invalid 'context': 或者chrome出現提示,您

http連續請求中Session丟失問題解決方案彙總

先說遇到的問題:同一套介面,iOS端的APP可以正常使用而Android端的APP不能使用(可以登入成功)。 初步除錯發現:Android端的APP登入成功後,後續的訪問取不到登入時儲存在session中的使用者資訊,而iOS是可以取到session中使用者資訊。 下面

Ambari叢集移動現有複製到另外地方或更改ip地址,導致各項服務元件上為黃色問號代表心跳丟失解決方案(圖文詳解)(博主推薦)

前言          最近,是在做叢集搬移工作,大家肯定會遇到如下的場景。          (1) 比如,你新購買的電腦,初步者學習使用Ambari叢集。從舊電腦複製到新電腦這邊來。          (2) 比如,你公司Ambari叢集的ip,因業務或其他情況需要,暫時需要更改ip。  

ViewPager 載入Fragment oncreatview() 方法重複呼叫最簡單解決方案

避免OncreatView()方法重複呼叫 vp = (NoScrollViewPager) findViewById(R.id.first_viewPager); vp.setOffscreenPageLimit(4); 解釋: private int mOffscr

springcloud fegin獲取request header解決方案

假設現在有A服務,B服務,外部使用RESTApi請求呼叫A服務,在請求頭上有token欄位,A服務使用完後,B服務也要使用,如何才能把token也轉發到B服務呢?這裡可以使用Feign的Reque

Windows7下安裝Qt5.6時提示msvcp120.dll丟失解決方案

這次在Windows7下安裝Qt5.6時,系統提示“因為計算機中丟失msvcp120.dll。 嘗試重新安裝該程式以解決此問題”,網上搜索後提示安裝Microsoft Visual C++ Redistributable 2013即可解決此問題。但按照提示去網上搜索下載安裝

mysql密碼修改與密碼丟失解決方案

密碼的修改 方法一:命令列中修改 mysqladmin -uroot -p password 'your_password' 方法二:進入mysql命令列用sql語句進行修改 這種方法適合於不記得root密碼之後進行修改。 注意這裡需使用passwor

ntoskrnl.exe損壞或丟失解決方案

  同事的電腦啟動時出現以下提示:“因以下檔案損壞或丟失Windows無法啟動 %systemroot%\system32\ntoskrnl.exe,請重新安裝以上檔案的拷貝”(Windows could not start because the following fi

Session丟失問題解決方案

.NET Framework 常規參考  <sessionState> 元素  為當前應用程式配置會話狀態設定。  <configuration>  <system.web>  <sessionState>  <ses

09.redis 哨兵主備切換時資料丟失解決方案

## 一、兩種資料丟失的情況 * * * ### 1. 非同步複製導致的資料丟失   因為master->slave的複製是非同步的,所以可能有部分資料還沒複製到slave,master就宕機了,此時這些部分資料就丟失了 ### 2. 腦裂導致的資料丟失 **腦裂是什麼** &em

feign呼叫session丟失解決方案

最近在做專案的時候發現,微服務使用feign相互之間呼叫時,存在session丟失的問題。例如,使用Feign呼叫某個遠端API,這個遠端API需要傳遞一個鑑權資訊,我們可以把cookie裡面的session資訊放到Header裡面,這個Header是動態的,跟