知識庫 / HTTP Client-Side RSS 訂閱

Feign 入門

HTTP Client-Side,JSON
HongKong
6
09:56 PM · Dec 05 ,2025

1. 概述

在本教程中,我們將介紹 Feign——由 Netflix 開發的聲明式 HTTP 客户端。

Feign 的目標是簡化 HTTP API 客户端。簡單來説,開發者只需要聲明和註解一個接口,實際的實現會在運行時提供。

2. 示例

在本文教程中,我們將使用一個示例 書店應用程序,該應用程序暴露了 REST API 端點。

我們可以輕鬆地克隆該項目並在本地運行它:

mvn install spring-boot:run

3. 安裝準備

首先,添加所需的依賴項:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>13.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
    <version>13.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-slf4j</artifactId>
    <version>13.1</version>
</dependency>

除了 feign-core 依賴項(它也被自動引入),我們還將使用一些插件,特別是 feign-okhttp 用於內部使用 Square 的 OkHttp 客户端來發起請求,feign-gson 用於使用 Google 的 GSON 作為 JSON 處理器,feign-slf4j 用於使用 Simple Logging Facade 進行請求日誌記錄。

為了實際獲得日誌輸出,我們需要在類路徑上配置我們喜歡的 SLF4J 支持的日誌記錄器實現。

在開始創建客户端接口之前,我們首先將設置一個 Book 模型,用於存儲數據:

public class Book {
    private String isbn;
    private String author;
    private String title;
    private String synopsis;
    private String language;

    // standard constructor, getters and setters
}

注意:JSON處理器至少需要一個“無參數構造函數”。

事實上,我們的REST提供程序是一個基於元數據的API,因此我們還需要一個簡單的包裝類:

public class BookResource {
    private Book book;

    // standard constructor, getters and setters
}

注意:我們將保持 BookResource 簡單,因為我們的示例 Feign 客户端並不能從超媒體特性中獲益!

4. 服務器端

為了理解如何定義 Feign 客户端,我們首先將研究 REST 提供者支持的方法和響應。

讓我們用一個簡單的 curl 命令行來列出所有書籍進行嘗試。

請記住,所有調用都必須以 /api 開頭,這對應於應用程序的 servlet-context。

curl http://localhost:8081/api/books

因此,我們將會得到一個完整的圖書倉庫,以JSON格式表示:

[
  {
    "book": {
      "isbn": "1447264533",
      "author": "Margaret Mitchell",
      "title": "Gone with the Wind",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/1447264533"
      }
    ]
  },

  ...

  {
    "book": {
      "isbn": "0451524934",
      "author": "George Orwell",
      "title": "1984",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/0451524934"
      }
    ]
  }
]

我們還可以通過將 ISBN 添加到 GET 請求中來查詢單個 圖書 資源:

curl http://localhost:8081/api/books/1447264533

5. Feign 客户端

最後,我們定義我們的 Feign 客户端。

我們將使用 @RequestLine 註解來指定 HTTP 方法和路徑部分作為參數。

參數將使用 @Param 註解進行建模:

public interface BookClient {
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("isbn") String isbn);

    @RequestLine("GET")
    List<BookResource> findAll();

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

注意: Feign 客户端只能用於消費基於文本的 HTTP API,這意味着它們無法處理二進制數據,例如文件上傳或下載。

好了! 現在我們將使用 Feign.builder() 來配置基於接口的客户端。

實際的實現將在運行時提供。

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

Feign 支持多種插件,例如 JSON/XML 編碼器和解碼器,或底層 HTTP 客户端,用於發起請求。

6. 單元測試

讓我們創建三個測試用例來測試我們的客户端。

請注意,我們使用靜態導入來引用 org.hamcrest.CoreMatchers.org.junit.Assert.

@Test
public void givenBookClient_shouldRunSuccessfully() throws Exception {
   List<Book> books = bookClient.findAll().stream()
     .map(BookResource::getBook)
     .collect(Collectors.toList());

   assertTrue(books.size() > 2);
}

@Test
public void givenBookClient_shouldFindOneBook() throws Exception {
    Book book = bookClient.findByIsbn("0151072558").getBook();
    assertThat(book.getAuthor(), containsString("Orwell"));
}

@Test
public void givenBookClient_shouldPostBook() throws Exception {
    String isbn = UUID.randomUUID().toString();
    Book book = new Book(isbn, "Me", "It's me!", null, null);
    bookClient.create(book);
    book = bookClient.findByIsbn(isbn).getBook();

    assertThat(book.getAuthor(), is("Me"));
}

7. 進一步閲讀

如果服務不可用時需要備用方案,我們可以將 HystrixFeign 添加到 classpath 中,並使用 HystrixFeign.builder() 構建我們的客户端。

查看該專門教程系列以瞭解更多關於 Hystrix 的信息。

此外,如果我們想將 Spring Cloud Netflix Hystrix 與 Feign 集成,這裏有一篇文章。

此外,還可以將客户端添加客户端負載均衡和/或服務發現。

我們可以通過將 Ribbon 添加到 classpath 中並使用構建器來實現:

BookClient bookClient = Feign.builder()
  .client(RibbonClient.create())
  .target(BookClient.class, "http://localhost:8081/api/books");

對於服務發現,我們需要啓用 Spring Cloud Netflix Eureka 構建我們的服務。然後,我們只需與 Spring Cloud Netflix Feign 集成。 這樣,我們就可以免費獲得 Ribbon 負載均衡。 更多信息請參考這裏。

8. 結論

在本文中,我們解釋瞭如何使用 Feign 構建聲明式 HTTP 客户端,以消費基於文本的 API。

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

發佈 評論

Some HTML is okay.