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

SpringCloud微服務(wù)調(diào)用丟失請(qǐng)求頭的問題及解決方案

 更新時(shí)間:2024年02月20日 14:31:26   作者:曬干的老咸魚  
在Spring Cloud 中微服務(wù)之間的調(diào)用會(huì)用到Feign,但是在默認(rèn)情況下,Feign 調(diào)用遠(yuǎn)程服務(wù)存在Header請(qǐng)求頭丟失問題,下面給大家分享SpringCloud微服務(wù)調(diào)用丟失請(qǐng)求頭的問題及解決方案,感興趣的朋友一起看看吧

在 Spring Cloud 中 微服務(wù)之間的調(diào)用會(huì)用到Feign,但是在默認(rèn)情況下,F(xiàn)eign 調(diào)用遠(yuǎn)程服務(wù)存在Header請(qǐng)求頭丟失問題。但基本上每個(gè)服務(wù)都會(huì)有一個(gè)全局globalId,能夠清除調(diào)用鏈路,可以有兩種解決方案

解決方案一

可以在每次遠(yuǎn)程調(diào)用時(shí),使用@RequestHeader注解重新封裝請(qǐng)求頭

    @GetMapping("/test")
    String test(String res, @RequestHeader String globalId);

解決方案二

可以使用springcloud提供的feign攔截器RequestInterceptor,攔截請(qǐng)求頭重新進(jìn)行封裝

package com.test.feignheader.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
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;
/**
 * @Description: feign攔截器功能, 解決header丟失問題
 **/
@Configuration
public class FeignConfig {
    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor() {
        RequestInterceptor requestInterceptor = new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1、使用RequestContextHolder拿到剛進(jìn)來的請(qǐng)求數(shù)據(jù)
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (requestAttributes != null) {
                    //老請(qǐng)求
                    HttpServletRequest request = requestAttributes.getRequest();
                    if (request != null) {
                        //2、同步請(qǐng)求頭的數(shù)據(jù)(主要是cookie)
                        //把老請(qǐng)求的cookie值放到新請(qǐng)求上來,進(jìn)行一個(gè)同步
                        String cookie = request.getHeader("Cookie");
                        template.header("Cookie", cookie);
                    }
                }
            }
        };
        return requestInterceptor;
    }
}

 也可以參考下面的代碼進(jìn)行封裝

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);
                //跳過 content-length,避免追加參數(shù)導(dǎo)致content-length值與實(shí)際長(zhǎng)度不一樣
                if (name.equals("content-length")) {
                   continue;
                }
                requestTemplate.header(name, values);
            }
        }
        /**  body一般不需要處理,否則會(huì)導(dǎo)致微服務(wù)調(diào)用異常
        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

也可以配置讓 某個(gè) FeignClient 使用這個(gè) FeignBasicAuthRequestInterceptor

feign:
  client:
    config:
      xxxx: # 遠(yuǎn)程服務(wù)名
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
        requestInterceptors: com.leparts.config.FeignBasicAuthRequestInterceptor

經(jīng)過測(cè)試,上面的解決方案可以正常的使用;但是出現(xiàn)了新的問題。

在轉(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

但信號(hào)量模式不是官方推薦的隔離策略;另一個(gè)解決方法就是自定義Hystrix的隔離策略。

自定義策略

HystrixConcurrencyStrategy 是提供給開發(fā)者去自定義hystrix內(nèi)部線程池及其隊(duì)列,還提供了包裝callable的方法,以及傳遞上下文變量的方法。所以可以繼承了HystrixConcurrencyStrategy,用來實(shí)現(xiàn)了自己的并發(fā)策略。

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

致此,F(xiàn)eign調(diào)用丟失請(qǐng)求頭的問題就解決的了 。

到此這篇關(guān)于SpringCloud微服務(wù)調(diào)用丟失請(qǐng)求頭的文章就介紹到這了,更多相關(guān)SpringCloud微服務(wù)調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用

    關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用

    這篇文章主要介紹了關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用,在SpringMVC中,數(shù)據(jù)綁定的工作是由 DataBinder 類完成的,DataBinder可以將HTTP請(qǐng)求中的數(shù)據(jù)綁定到Java對(duì)象中,需要的朋友可以參考下
    2023-07-07
  • Java多線程的原子性,可見性,有序性你都了解嗎

    Java多線程的原子性,可見性,有序性你都了解嗎

    這篇文章主要為大家詳細(xì)介紹了Java多線程的原子性,可見性,有序性,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • java向文件末尾添加內(nèi)容示例分享

    java向文件末尾添加內(nèi)容示例分享

    本文為大家提供一個(gè)java向文件末尾添加內(nèi)容的示例分享,大家參考使用吧
    2014-01-01
  • Java dom4j創(chuàng)建解析xml文檔過程解析

    Java dom4j創(chuàng)建解析xml文檔過程解析

    這篇文章主要介紹了Java dom4j創(chuàng)建解析xml文檔過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java集成大模型LangChain4j實(shí)戰(zhàn)完全指南(推薦)

    Java集成大模型LangChain4j實(shí)戰(zhàn)完全指南(推薦)

    LangChain4j 的目標(biāo)是簡(jiǎn)化將大語言模型(LLM - Large Language Model)集成到Java應(yīng)用程序中的過程,本文給大家介紹Java集成大模型LangChain4j實(shí)戰(zhàn)完全指南,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Spring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解

    Spring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解

    下面小編就為大家?guī)硪黄猄pring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • 使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn)

    使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn)

    這篇文章主要介紹了使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 一小時(shí)迅速入門Mybatis之bind與多數(shù)據(jù)源支持 Java API

    一小時(shí)迅速入門Mybatis之bind與多數(shù)據(jù)源支持 Java API

    這篇文章主要介紹了一小時(shí)迅速入門Mybatis之bind與多數(shù)據(jù)源支持 Java API,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Mybatis foreach用法解析--對(duì)于list和array

    Mybatis foreach用法解析--對(duì)于list和array

    這篇文章主要介紹了Mybatis foreach用法解析--對(duì)于list和array,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • base64_encode和base64_decode的JAVA實(shí)現(xiàn)

    base64_encode和base64_decode的JAVA實(shí)現(xiàn)

    Base64 編碼其實(shí)是將3個(gè)8位字節(jié)轉(zhuǎn)換為4個(gè)6位這4個(gè)六位字節(jié) 其實(shí)仍然是8位,只不過高兩位被設(shè)置為0. 當(dāng)一個(gè)字節(jié)只有6位有效時(shí),它的取值空間為0 到 2的6次方減1 即63,也就是說被轉(zhuǎn)換的Base64編碼的每一個(gè)編碼的取值空間為(0~63).需要的朋友可以參考下
    2016-04-04

最新評(píng)論

定陶县| 千阳县| 大安市| 石渠县| 张家界市| 南开区| 泸州市| 靖安县| 岫岩| 新闻| 高州市| 安康市| 清丰县| 湟源县| 金寨县| 长武县| 桃园市| 大洼县| 敦煌市| 沙雅县| 铅山县| 聂拉木县| 临江市| 齐河县| 元朗区| 泰兴市| 托克逊县| 珠海市| 进贤县| 南昌市| 梨树县| 修水县| 开封市| 紫云| 阳信县| 旌德县| 大理市| 腾冲县| 兴海县| 小金县| 罗田县|