使用Feign傳送HTTP請求
在往常的 HTTP 呼叫中,一直都是使用的官方提供的 RestTemplate 來進行遠端呼叫,該呼叫方式將組裝程式碼冗餘到正常業務程式碼中,不夠優雅,因此在接觸到 Feign 後,考慮使其作為一個 HTTP 傳送基礎,來進行遠端呼叫。
下面就讓我們來看一下,其是如何使用的。
引入依賴
首先,我們需要將 Feign 的基礎依賴引入專案,因為我們只使用 Feign 的 remote 功能,因此,只引入基礎依賴。
此外在專案中,我們還自定義了了 JSON 轉換和 log 設定,因此還需要引入這些的第三方依賴,如下所示。
<!-- feign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.10.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>10.10.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>10.10.1</version>
</dependency>
傳送路徑和方法設定
然後,因為 Feign 是一種申明式的呼叫,因此我們需要配置傳送的介面路徑和傳送介面定義,看下面的例子。
@RequestLine("GET /user/getone?arkOrgId={arkOrgId}&userId={userId}")
JSONObject getOneStaff(@Param("arkOrgId") String arkOrgId,@Param("userId") String userId);
@RequestLine("POST /user/add")
@Headers("Content-Type: application/json")
@Body("{body}")
JSONObject saveStaff(@Param("body") SaveEmployeeDTO saveEmployeeDTO);
在程式碼例項中,我們定義了兩種傳送的例項,一種是 GET 請求,一種是 POST 請求,下面,我們分別來看一下其中的程式碼的作用是什麼。
- @RequestLine:定義傳送方式和傳送介面定義,其中用 GET 和 POST 來定義傳送方式,然後空格後,寫上 servelt path(context path 和域名或ip埠號在其他地方配置);
- {}:用來作為佔位符,動態填充需要的引數;
- @Param:用來匹配 URI 中的佔位符;
- @Headers("Content-Type: application/json"):構建請求表頭,在 POST 請求中,需要宣告該請求的傳送格式為 json;
- @Body:POST 請求,需要標註請求體;
- JSONObject:在本例項中,採用是一個通用的 json 物件來接收,方便統一,在自己的程式碼中,也可以定義一個接受實體類來接受,作用是一樣的。
POST 請求,需要在實體中重寫 toString() 方法,使其在傳送時呼叫該方法後,是一個 JSON 字串,詳細見後文 Tips 中寫的。
定義傳送客戶端
@Configuration
public class FeignConfig {
public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Value("${staff.base.url}")
private String staffBaseUrl;
@Bean
public StaffFeignService staffFeignService() {
GsonBuilder builder = new GsonBuilder();
builder.setDateFormat(DATE_TIME_FORMAT);
return Feign.builder()
.retryer(closeFeignRetry())
.decoder(new GsonDecoder(builder.create()))
.encoder(new GsonEncoder())
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(StaffFeignService.class, staffBaseUrl);
}
/**
* 關閉feign的失敗重試功能
*/
@Bean
public Retryer closeFeignRetry() {
return Retryer.NEVER_RETRY;
}
@Bean
public Request.Options options() {
return new Request.Options(15000, 30000);
}
}
緊接著,我們來定義傳送客戶端。
首先,我們採用 @Value
來動態新增路由,這樣,就可以根據在配置檔案中的屬性來新增 context path,從而做到可擴充。
然後,feign 的很多配置都是可以根據自身專案需要在 DIY 的,因此在這裡,我們配置了編解碼採用 GSON 的編解碼器,日誌級別設定全列印。通過該設定來生成一個 Feign 客戶端。
Feign 官方文件,在官方文件中,有詳細的配置說明,根據自身需要使用,即可。
使用
@Autowired
StaffFeignService staffFeignService;
// get 請求
JSONObject saveSingleQrCode = staffFeignService.saveSingleQrCode(userId);
// post 請求
SaveMultiQrCodesDTO saveMultiQrCodesDTO = new SaveMultiQrCodesDTO();;
JSONObject saveMultiQrCodes = staffFeignService.saveMultiQrCodes(saveMultiQrCodesDTO);
Tips
記錄一些在使用中的重點,需要注意。
重寫 toString() 方法
在傳送 JSON 時,需要重寫 toString() 方法,否則會導致接受方,無法用 json 進行解析。
@Override
public String toString() {
return JSON.toJSONString(this);
}
非同步客戶端
有時候,我們使用非同步傳送,從而不影響我們的主體業務,Feign 也支援該種配置。
@Bean
public IHermesFeignService hermesFeignService() {
GsonBuilder builder = new GsonBuilder();
builder.setDateFormat(DATE_TIME_FORMAT);
return AsyncFeign.asyncBuilder()
.decoder(new GsonDecoder(builder.create()))
.encoder(new GsonEncoder(builder.create()))
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(IHermesFeignService.class, hermesBaseUrl);
}
重點,就是在構建 Feign 時,採用 AsyncFeign.asyncBuilder()
來進行構建。
公眾號截圖
文章在公眾號「iceWang」第一手更新,有興趣的朋友可以關注公眾號,第一時間看到筆者分享的各項知識點,謝謝!筆芯!