知識庫 / REST RSS 訂閱

使用Feign設置請求頭

REST
HongKong
4
03:36 AM · Dec 06 ,2025

1. 概述

有時,在使用 Feign 時,我們需要在 HTTP 調用中設置請求頭。Feign 允許我們使用聲明式語法構建 HTTP 客户端。

在本教程中,我們將學習如何使用註解配置請求頭。我們還將學習如何通過攔截器包含常用的請求頭。

2. 示例

在本文教程中,我們將使用一個示例,該示例暴露了 REST API 端點:書店應用程序。您可以輕鬆克隆項目並在本地運行它:

$ mvn install spring-boot:run

讓我們深入探討客户端實現。

3. 使用 Header 註解

讓我們考慮一個場景,其中特定的 API 調用始終應包含靜態 Header。在這種情況下,我們可能會將該請求 Header 配置為客户端的一部分。一個典型的例子是包含 Content-Type Header。

使用 @Header 註解,我們可以輕鬆配置靜態請求 Header。 我們可以靜態地或動態地定義該 Header 值。

3.1. 設置靜態頭部值

讓我們配置兩個靜態頭部,即<em >Accept-Language</em ><em >Content-Type</em >,到<em >BookClient</em >中:

@Headers("Accept-Language: en-US")
public interface BookClient {
    
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("isbn") String isbn);

    @RequestLine("POST")
    @Headers("Content-Type: application/json")
    void create(Book book);
}

在上述代碼中,Accept-Language 標頭包含在所有 API 中,因為它應用於 BookClient。然而,create 方法還包含額外的 Content-Type 標頭。

接下來,讓我們看看如何使用 Feign 的 Builder 方法創建 BookClient,並傳遞 HEADERS 日誌級別:

Feign.builder()
  .encoder(new GsonEncoder())
  .decoder(new GsonDecoder())
  .logger(new Slf4jLogger(type))
  .logLevel(Logger.Level.HEADERS)
  .target(BookClient.class, "http://localhost:8081/api/books");

現在,讓我們測試 create 方法:

String isbn = UUID.randomUUID().toString();
Book book = new Book(isbn, "Me", "It's me!", null, null);
        
bookClient.create(book);

book = bookClient.findByIsbn(isbn).getBook();

然後,讓我們驗證輸出日誌中的頭部:

18:01:15.039 [main] DEBUG c.b.f.c.h.staticheader.BookClient - [BookClient#create] Accept-Language: en-US
18:01:15.039 [main] DEBUG c.b.f.c.h.staticheader.BookClient - [BookClient#create] Content-Type: application/json
18:01:15.096 [main] DEBUG c.b.f.c.h.staticheader.BookClient - [BookClient#findByIsbn] Accept-Language: en-US

請注意,如果客户端接口和API方法中標頭名稱相同,則它們不會相互覆蓋。相反,請求將包含所有這些值。

3.2. 設置動態請求頭值

使用 <em >@Header</em> 註解,我們還可以設置動態請求頭值。為此,我們需要將值表達為佔位符。

<em >x-requester-id</em> 請求頭包含到 <em >BookClient</em> 中,佔位符為 <em >requester</em>

@Headers("x-requester-id: {requester}")
public interface BookClient {
   
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("requester") String requester, @Param("isbn") String isbn);
}

我們創建了一個名為 x-requester-id 的變量,並將其傳遞到每個方法中。我們使用 @Param 註解來匹配變量名。它會在運行時擴展以滿足由 @Headers 註解指定的頭部。

現在,讓我們使用 BookClient API,並添加 x-requester-id 頭部:

String requester = "test";
book = bookClient.findByIsbn(requester, isbn).getBook();

然後,讓我們在輸出日誌中驗證請求頭:

18:04:27.515 [main] DEBUG c.b.f.c.h.s.parameterized.BookClient - [BookClient#findByIsbn] x-requester-id: test

4. 使用 HeaderMaps 註解

讓我們設想一個場景,其中 header 鍵和值都是動態的。在這種情況下,可能的鍵範圍事先是未知的。此外,在同一客户端的不同方法調用之間,header 也可能不同。一個典型的例子是設置某些元數據 header。

使用一個 Map 參數,並使用 @HeaderMap,可以設置動態 header:

@RequestLine("POST")
void create(@HeaderMap Map<String, Object> headers, Book book);

現在,讓我們嘗試使用 header map 測試 create 方法:

Map<String,Object> headerMap = new HashMap<>();
    	
headerMap.put("metadata-key1", "metadata-value1");
headerMap.put("metadata-key2", "metadata-value2");
    	
bookClient.create(headerMap, book);

然後,讓我們驗證輸出日誌中的標頭:

18:05:03.202 [main] DEBUG c.b.f.c.h.dynamicheader.BookClient - [BookClient#create] metadata-key1: metadata-value1
18:05:03.202 [main] DEBUG c.b.f.c.h.dynamicheader.BookClient - [BookClient#create] metadata-key2: metadata-value2

5. 請求攔截器

攔截器可以對每個請求或響應執行各種隱式任務,例如日誌記錄或身份驗證。

Feign 提供了一個 RequestInterceptor 接口。 通過此接口,我們可以添加請求頭。

當已知請求頭應包含在每個調用中時,添加一個請求攔截器是有意義的。 這種模式消除了調用代碼實施非功能性要求(如身份驗證或跟蹤)的依賴性。

讓我們通過實現一個 AuthorisationService 來嘗試一下,該服務將用於生成授權令牌:

public class ApiAuthorisationService implements AuthorisationService {

    @Override
    public String getAuthToken() {
        return "Bearer " + UUID.randomUUID();
    }
}

現在,讓我們來實現我們的自定義請求攔截器:

public class AuthRequestInterceptor implements RequestInterceptor {
	
    private AuthorisationService authTokenService;
   
    public AuthRequestInterceptor(AuthorisationService authTokenService) {
        this.authTokenService = authTokenService;
    }

    @Override
    public void apply(RequestTemplate template) {
        template.header("Authorisation", authTokenService.getAuthToken());
    }
}

請注意,請求攔截器可以讀取、刪除或修改任何請求模板的任何部分。

現在,讓我們使用builder方法將AuthInterceptor添加到BookClient中:

Feign.builder()
  .requestInterceptor(new AuthInterceptor(new ApiAuthorisationService()))
  .encoder(new GsonEncoder())
  .decoder(new GsonDecoder())
  .logger(new Slf4jLogger(type))
  .logLevel(Logger.Level.HEADERS)
  .target(BookClient.class, "http://localhost:8081/api/books");

然後,讓我們使用帶有 Authorisation 標頭的 BookClient API 進行測試:

bookClient.findByIsbn("0151072558").getBook();

現在,讓我們驗證輸出日誌中的標題:

18:06:06.135 [main] DEBUG c.b.f.c.h.staticheader.BookClient - [BookClient#findByIsbn] Authorisation: Bearer 629e0af7-513d-4385-a5ef-cb9b341cedb5

可同時應用於 Feign 客户端的多個請求攔截器。但對於它們應用的順序,並未提供任何保證。

6. 結論

在本文中,我們探討了 Feign 客户端如何支持設置請求頭。我們通過使用 <em @Headers</em><em @HeaderMaps</em>> 註解以及請求攔截器來實現這一功能。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.