使用Feign發送HTTP請求

使用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」第一手更新,有興趣的朋友可以關注公眾號,第一時間看到筆者分享的各項知識點,謝謝!筆芯!

Tags: