知識庫 / Spring / Spring Cloud RSS 訂閱

使用 OpenFeign 設置 HTTP Patch 請求

Spring Cloud
HongKong
6
11:33 AM · Dec 06 ,2025

1. 概述

當通過 REST API 更新對象時,使用 PATCH 方法是一種最佳實踐。這允許我們使用要修改的字段進行部分更新。我們也可以使用 PUT 方法,當現有資源需要完全更改時。

在本教程中,我們將學習如何在 OpenFeign 中設置 HTTP PATCH 方法。我們還將遇到在測試 Feign 客户端的 PATCH 方法時出現意外錯誤。

最後,我們將瞭解根本原因並解決問題。

2. Spring Boot 示例應用程序

讓我們假設我們需要構建一個簡單的微服務,該微服務會調用下游服務以執行部分更新。

2.1. Maven 依賴

首先,我們將添加以下 Maven 依賴:spring-boot-starter-webspring-cloud-starter-openfeign 。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.2. 實現 Feign 客户端

現在,讓我們使用 Spring 的 web 註解,在 Feign 中實現 PATCH 方法。

首先,讓我們使用少量屬性對 User 類進行建模:

public class User {
    private String userId;
    private String userName;
    private String email;
}

接下來,我們將實現 UserClient 接口,並使用 updateUser 方法:

@FeignClient(name = "user-client", url = "http://localhost:8082/api/user")
public interface UserClient {
    @RequestMapping(value = "{userId}", method = RequestMethod.PATCH)
    User updateUser(@PathVariable(value = "userId") String userId, @RequestBody User user);
}

在上述 PATCH 方法中,我們傳遞的是僅包含所需字段的 User 對象,以及 userId 字段。 這樣比發送整個資源表示形式更簡潔,節省了網絡帶寬,並且避免了在同一對象的不同字段上同時進行更新時產生的競爭。

與之相反,如果我們使用 PUT 請求,則必須傳遞完整的資源表示形式來替換現有資源。

3. 實現對 Feign 客户端的測試

現在,我們將通過模擬 HTTP 調用來為 UserClient 實現一個測試用例。

3.1. 設置 WireMock 服務器

為了進行實驗,我們需要使用一個 Mocking 框架來模擬我們所調用的服務。

首先,讓我們包含 WireMockServer Maven 依賴項:

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-jre8</artifactId>
    <version>2.35.0</version>
    <scope>test</scope>
</dependency>

然後,讓我們配置並啓動WireMockServer

WireMockServer wireMockServer = new WireMockServer(8082);
configureFor("localhost", 8082);
wireMockServer.start();

WireMockServer 在配置的 Feign 客户端所使用的相同 hostport 上啓動。

3.2. 模擬 PATCH API

我們將模擬 PATCH 方法,以測試更新 用户 API:

String updatedUserResponse = "{\n" +
    "\"userId\": 100001,\n" +
    "\"userName\": \"name\",\n" +
    "\"email\": \"[email protected]\"\n" +
    "}";
stubFor(patch(urlEqualTo("/api/user/".concat(USER_ID)))
  .willReturn(aResponse().withStatus(HttpStatus.OK.value())
  .withHeader("Content-Type", "application/json")
  .withBody(updatedUserResponse)));

3.3. 測試 PATCH 請求

為了進行測試,我們將 User 對象傳遞給 UserClient,並提供用於更新所需的字段。

現在,讓我們完成測試並驗證更新功能:

User user = new User();
user.setUserId("100001");
user.setEmail("[email protected]");
User updatedUser = userClient.updateUser("100001", user);

assertEquals(user.getUserId(), updatedUser.getUserId());
assertEquals(user.getEmail(), updatedUser.getEmail());

預計上述測試應該通過。然而,我們將會從Feign客户端收到一個意外錯誤:

feign.RetryableException: Invalid HTTP method: PATCH executing PATCH http://localhost:8082/api/user/100001
        at feign.FeignException.errorExecuting(FeignException.java:268)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:131)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:91)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
	at jdk.proxy2/jdk.proxy2.$Proxy80.updateUser(Unknown Source)
	at com.baeldung.cloud.openfeign.patcherror.client.UserClientUnitTest.givenUserExistsAndIsValid_whenUpdateUserCalled_thenReturnSuccess(UserClientUnitTest.java:64)
	...

接下來,我們來詳細調查一下這個錯誤。

3.4. 無效 HTTP 方法錯誤的根源

上述錯誤信息表明請求的 HTTP 方法無效。儘管根據 HTTP 規範,PATCH 方法是有效的。

從錯誤信息中可以看出,該問題是由 ProtocolException 類引起的,並由 HttpURLConnection 類傳播的。

Caused by: java.net.ProtocolException: Invalid HTTP method: PATCH
	at java.base/java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:489)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(HttpURLConnection.java:598)
	at feign.Client$Default.convertAndSend(Client.java:170)
	at feign.Client$Default.execute(Client.java:104)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:119)

事實證明,默認的 HTTP 客户端使用 HttpURLConnection 類來建立 HTTP 連接。 HttpURLConnection 類包含一個 setRequestMethod 方法,用於設置請求方法。

不幸的是,HttpURLConnection 類不識別 PATCH 方法作為有效類型。

4. 修復 PATCH 方法錯誤

為了解決此錯誤,我們將添加一個支持的 HTTP 客户端依賴項。同時,我們將通過添加配置來覆蓋默認的 HTTP 客户端。

4.1. 添加 OkHttpClient 依賴

讓我們添加 feign-okhttp 依賴:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

我們應指出,任何其他支持的HTTP客户端,例如ApacheHttpClient, 也會正常工作。

4.2. 啓用 OkHttpClient

OkHttpClient 類將 PATCH 方法視為有效類型,不會拋出任何異常。

以下配置可用於啓用 OkHttpClient 類:

feign.okhttp.enabled=true

最後,我們將重新運行測試並驗證 PATCH 方法是否有效。現在,Feign 客户端沒有收到任何錯誤:

UserClientUnitTest.givenUserExistsAndIsValid_whenUpdateUserCalled_thenReturnSuccess: 1 total, 1 passed

5. 結論

在本文中,我們學習瞭如何使用 OpenFeign 中的 PATCH 方法。我們還發現了一個意外錯誤,並瞭解了其根本原因。

我們還使用 OkHttpClient 實現解決了該問題。

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

發佈 評論

Some HTML is okay.