使用 OpenFeign 設置 Http 補丁請求
1. 概述
通過 REST API 更新對象時,最好使用PATCH方法。這允許我們使用我們希望更改的字段執行部分更新。當現有資源需要完全更改時,我們還可以使用 PUT 方法。
在本教程中,我們將學習如何在OpenFeign中設置 HTTP PATCH 方法。在Feign客戶端中測試 PATCH 方法時,我們還會看到意外錯誤。
最後,我們將了解根本原因並解決問題。
2. Spring Boot中的示例應用
假設我們需要構建一個簡單的微服務來調用下游服務來進行部分更新。
2.1. Maven 依賴項
首先,我們將添加[spring-boot-starter-web](https://central.sonatype.com/search?q=spring-boot-starter-web)
和spring-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.實施假客戶端
現在,我們使用 Spring Web 註解在 Feign 中實現 PATCH 方法。
首先,讓我們用一些屬性來建模User
類:
public class User {
private String userId;
private String userName;
private String email;
}
接下來,我們將使用updateUser
方法實現UserClient interface
:
@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
對像以及u
serId
。它比發送整個資源表示更方便,節省了一些網絡帶寬,並避免了跨不同字段對同一對象進行多個更新時的爭用。
相反,如果我們使用 PUT 請求,則必須傳遞完整的資源表示來替換現有資源。
3. 對 Feign 客戶端進行測試
現在讓我們通過模擬 HTTP 調用來實現UserClient
的測試用例。
3.1.設置 WireMock 服務器
為了進行實驗,我們需要使用模擬框架來模擬我們正在調用的服務。
首先,讓我們包含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 客戶端配置使用的WireMockServer
host
和port
上啟動。
3.2.存根 PATCH API
我們將模擬 PATCH 方法來測試更新User
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
設置請求方法。
不幸的是, 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
實現解決了該問題。
與往常一樣,示例代碼可以在 GitHub 上找到。