使用 Feign 設置請求頭
- Feign
- java
一、概述
有時我們需要在使用 Feign 時在 HTTP 調用中設置請求頭。 Feign 允許我們使用聲明式語法簡單地構建 HTTP 客戶端。
在這個簡短的教程中,我們將看到如何使用註釋配置請求標頭。我們還將了解如何使用攔截器包含常見的請求標頭。
2. 例子
在本教程中,我們將使用一個公開 REST API 端點的示例書店應用程序。
我們可以輕鬆地克隆項目並在本地運行它:
$ mvn install spring-boot:run
讓我們深入了解客戶端的實現。
3. 使用Header
註解
讓我們考慮一個特定的 API 調用應該始終包含靜態標頭的場景。在這種情況下,我們可以將該請求標頭配置為客戶端的一部分。一個典型的例子是包含一個Content-Type
標頭。
使用@Header
註解,我們可以輕鬆配置靜態請求頭。我們可以靜態或動態定義此標頭值。
3.1 設置靜態標題值
讓我們在BookClient
中配置兩個靜態標題,即Accept-Language
和Content-Type,
:
@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 cbfchstaticheader.BookClient - [BookClient#create] Accept-Language: en-US
18:01:15.039 [main] DEBUG cbfchstaticheader.BookClient - [BookClient#create] Content-Type: application/json
18:01:15.096 [main] DEBUG cbfchstaticheader.BookClient - [BookClient#findByIsbn] Accept-Language: en-US
需要注意的是,如果客戶端接口和 API 方法中的 header 名稱相同,則它們不會相互覆蓋。相反,請求將包括所有這些值。
3.2.設置動態標題值
使用@Header
註解,我們還可以設置動態的標頭值。為此,我們需要將值表示為佔位符。
讓我們將x-requester-id
標頭包含到BookClient
中,並帶有requester
的佔位符:
@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
註釋指定的標頭。
現在,讓我們使用x-requester-id
標頭調用BookClient
API:
String requester = "test";
book = bookClient.findByIsbn(requester, isbn).getBook();
然後,讓我們在輸出記錄器中驗證請求標頭:
18:04:27.515 [main] DEBUG cbfchsparameterized.BookClient - [BookClient#findByIsbn] x-requester-id: test
4. 使用HeaderMaps
註解
讓我們想像一個標題鍵和值都是動態的場景。在這種情況下,可能的密鑰範圍提前是未知的。此外,在同一客戶端上的不同方法調用之間,標頭可能會有所不同。一個典型的例子是設置某些元數據標頭。
使用Map
@HeaderMap
註釋的 Map 參數設置動態標題:
@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 cbfchdynamicheader.BookClient - [BookClient#create] metadata-key1: metadata-value1
18:05:03.202 [main] DEBUG cbfchdynamicheader.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
方法將BookClient
添加到AuthInterceptor
:
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 cbfchstaticheader.BookClient - [BookClient#findByIsbn] Authorisation: Bearer 629e0af7-513d-4385-a5ef-cb9b341cedb5
多個請求攔截器也可以應用於Feign 客戶端。儘管對它們的應用順序沒有提供任何保證。
六,結論
在本文中,我們討論了 Feign 客戶端如何支持設置請求標頭。我們使用@Headers
、 @HeaderMaps
註釋和請求攔截器實現了這一點。