欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Feign遠(yuǎn)程調(diào)用丟失請求頭問題

 更新時間:2024年09月29日 15:02:12   作者:頭未禿  
本文介紹了在服務(wù)端項目中如何解決資源訪問限制問題,首先介紹了問題的產(chǎn)生,然后詳細(xì)解析了源碼,最后提出了解決方案,解決方案包括同步和異步兩種,同步時直接向Spring容器注入RequestInterceptor攔截器

前言

我們在寫服務(wù)端項目的時候,總會限制對某些資源的訪問,最常見的就是要求用戶先登錄才能訪問資源,當(dāng)用戶登錄后就會將此次會話信息保存進(jìn)session,同時返回給瀏覽器指定的cookie鍵值,下次瀏覽器再次訪問,請求頭中就會攜帶這個cookie,我們也以次來識別用戶的登錄狀態(tài),做出正確響應(yīng)。

問題

有時候,我們先行登錄,然后訪問服務(wù)A的某個方法,請求頭中攜帶cookie,標(biāo)識我們已經(jīng)登錄。

但若是我們訪問的目標(biāo)方法在執(zhí)行過程中使用feign進(jìn)行遠(yuǎn)程調(diào)用服務(wù)B,而服務(wù)B也要先判斷登錄狀態(tài),我們可能發(fā)現(xiàn)服務(wù)B會調(diào)用失敗,或者說拿不到數(shù)據(jù),理由是服務(wù)B認(rèn)為我們并未登錄。

而這時,如果我們直接從瀏覽器訪問服務(wù)B的這個方法卻能得到一個成功的響應(yīng)。

查看源碼

1、使用feign進(jìn)行遠(yuǎn)程調(diào)用時,首先判斷目標(biāo)方法類型,如果是 toString(),hashCode(),equals()這幾個方法,那就是本地直接完成了

2、執(zhí)行真正的遠(yuǎn)程調(diào)用的方法

3、根據(jù)模板template來創(chuàng)建請求request(默認(rèn)的情況feign是不會幫我們把原請求頭參數(shù)復(fù)制到新請求的請求頭上的),然后進(jìn)行客戶端client調(diào)用

4、但是創(chuàng)建請求時,會先調(diào)用所有的攔截器RequestInterceptors

5、所以我們可以自己向容器中注冊一個攔截器RequestInterceptor,在這個攔截器中重寫apply方法,在apply方法中把老請求的cookie復(fù)制到新request的請求頭中,完成請求頭的同步。(然后targetRequest 方法就會調(diào)用攔截器的apply方法,進(jìn)行返回)

總結(jié):

feign遠(yuǎn)程調(diào)用,自己創(chuàng)建一個新的request對象,按照指定的路徑和參數(shù)發(fā)起新的請求,并得到響應(yīng)結(jié)果。但是這個新的request對象請求頭為空,所以丟失了原先請求中的數(shù)據(jù)。

feign在創(chuàng)建新的request對象時,會調(diào)用一系列容器中的RequestInterceptor對象,執(zhí)行其apply方法,對這個創(chuàng)建好的request進(jìn)行增強,再去真正執(zhí)行請求。但是默認(rèn)情況下容器中不存在這類攔截器對象。

我們可以自己向容器中注冊一個RequestInterceptor,在其apply方法體內(nèi),獲取到原始request,將其數(shù)據(jù)取出,賦值到新的request中,完成請求頭的同步。RequestContextHolder借助ThreadLocal將每一個原始請求與tomcat為其分配的線程綁定,之后,只要在同個線程內(nèi),隨時隨地都可輕易獲取到原始request。而我們是在apply方法體內(nèi),通過 RequestContextHolder.getRequestAttributes() 獲取的。RequestContextHolder是借助ThreadLocal將每一個原始請求與tomcat為其分配的線程綁定,之后,只要在同個線程內(nèi),隨時隨地都可輕易獲取到原始request。

解決

1、同步時

直接向spring容器注入RequestInterceptor攔截器即可

/**
* Feign
* @return
*/
@Bean
public RequestInterceptor requestInterceptor(){
   return requestTemplate -> {
       //1、從RequestContextHolder獲取原始請求的請求數(shù)據(jù)(請求參數(shù)、請求頭等)
       ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
       HttpServletRequest request = attributes.getRequest();
       //2、同步請求頭數(shù)據(jù)
       Enumeration<String> headerNames = request.getHeaderNames();
       if (headerNames != null) {
           while (headerNames.hasMoreElements()) {
               String name = headerNames.nextElement();
               String values = request.getHeader(name);
               // 跳過 content-length,沒有跳過會導(dǎo)致請求參數(shù)無法接收
               if (HttpHeaderConsts.CONTENT_LENGTH.equalsIgnoreCase(name)) {
                   continue;
               }
               requestTemplate.header(name, values);
           }
       }
   };
}

2、異步時

如果請求中使用了異步,也就是多線程,就算配置了上面的配置也會導(dǎo)致feign請求頭丟失,因為請求頭信息是通過threadLocal保存的,也就是只有在同一個線程中才能使用請求中的請求頭并且同步初始請求頭信息到feign請求中

解決辦法

在異步調(diào)用時主動將請求頭覆蓋到異步線程的請求上下文中

// 通過請求上下文獲取請求信息
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
    // 遠(yuǎn)程查詢所有的收貨地址列表
    // 在該線程中添加請求信息
    RequestContextHolder.setRequestAttributes(requestAttributes);
    List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
    orderConfirmVo.setAdress(address);
}, executor);
?
CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
    // 遠(yuǎn)程查詢購物車所有選中的購物想
    // 在該線程中添加請求信息
    RequestContextHolder.setRequestAttributes(requestAttributes);
    List<OrderItemVo> currentUserItems = cartFeignService.getCurrentUserItems();
    orderConfirmVo.setItems(currentUserItems);
}, executor);

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis處理mysql主鍵自動增長出現(xiàn)的不連續(xù)問題解決

    MyBatis處理mysql主鍵自動增長出現(xiàn)的不連續(xù)問題解決

    本文主要介紹了MyBatis處理mysql主鍵自動增長出現(xiàn)的不連續(xù)問題解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 深入理解Java設(shè)計模式之組合模式

    深入理解Java設(shè)計模式之組合模式

    這篇文章主要介紹了JAVA設(shè)計模式之組合模式的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2021-11-11
  • SpringCloud Eureka搭建的方法步驟

    SpringCloud Eureka搭建的方法步驟

    這篇文章主要介紹了SpringCloud Eureka搭建的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • SpringCloud?GateWay網(wǎng)關(guān)示例代碼詳解

    SpringCloud?GateWay網(wǎng)關(guān)示例代碼詳解

    這篇文章主要介紹了SpringCloud?GateWay網(wǎng)關(guān),Spring?cloud?Gateway的功能很多很強大,文中提到了Spring?Cloud?Gateway中幾個重要的概念,結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-04-04
  • springboot @ConfigurationProperties和@PropertySource的區(qū)別

    springboot @ConfigurationProperties和@PropertySource的區(qū)別

    這篇文章主要介紹了springboot @ConfigurationProperties和@PropertySource的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Netty網(wǎng)絡(luò)編程實戰(zhàn)之開發(fā)聊天室功能

    Netty網(wǎng)絡(luò)編程實戰(zhàn)之開發(fā)聊天室功能

    這篇文章主要為大家詳細(xì)介紹了如何利用Netty實現(xiàn)聊天室功能,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Netty網(wǎng)絡(luò)編程有一定幫助,需要的可以參考一下
    2022-10-10
  • Java實現(xiàn)并查集示例詳解

    Java實現(xiàn)并查集示例詳解

    這篇文章主要通過一個題目示例為大家詳細(xì)介紹Java如何實現(xiàn)并查集,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • MyBatis異常-Property ''configLocation'' not specified, using default MyBatis Configuration

    MyBatis異常-Property ''configLocation'' not specified, using d

    今天小編就為大家分享一篇關(guān)于MyBatis異常-Property 'configLocation' not specified, using default MyBatis Configuration,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • springboot集成RocketMQ過程及使用示例詳解

    springboot集成RocketMQ過程及使用示例詳解

    這篇文章主要為大家介紹了springboot集成RocketMQ過程及使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Java+Swing實現(xiàn)中國象棋游戲

    Java+Swing實現(xiàn)中國象棋游戲

    這篇文章將通過Java+Swing實現(xiàn)經(jīng)典的中國象棋游戲。文中可以實現(xiàn)開始游戲,悔棋,退出等功能。感興趣的小伙伴可以跟隨小編一起動手試一試
    2022-02-02

最新評論