【解決方案】如何使用 Http API 代替 OpenFeign 進行遠程服務調用

来源:https://www.cnblogs.com/Apluemxa/p/17979942
-Advertisement-
Play Games

看到標題大家可能會有點疑惑吧:OpenFeign 不是挺好用的嗎?尤其是微服務之間的遠程調用,平時用的也挺習慣的,為啥要替換呢? ...


目錄

前言

看到標題大家可能會有點疑惑吧:OpenFeign 不是挺好用的嗎?尤其是微服務之間的遠程調用,平時用的也挺習慣的,為啥要替換呢?

背景和原因是這樣的:

  1. 部門/團隊在安全性上有所考慮,即儘可能地減少/消除引入外部依賴,儘量只使用自研依賴、apache、Spring等必須的開源依賴;
  2. 而 OpenFeign 的使用則是引入了 Spring Cloud 依賴(不在安全要求範圍內),所以需要考慮替換;
  3. 為以後團隊的項目上 Spring 6做鋪墊,Spring 6 會有 Spring 內置的 Http Interface 發起遠程服務調用。

下麵將從介紹 OpenFeign、常見的 Http API 以及重點介紹 Spring 自帶的 RestTemplate Http 模板這3個方面展開。


一、何為OpenFeign

OpenFeign 是 Spring Cloud 在 Feign 的基礎上支持了 SpringMVC 的註解,如 @RequesMapping 等,其底層預設使用的是 URLConnection 實現。

OpenFeign 的 @FeignClient 註解可以解析 SpringMVC 的@RequestMapping 註解下的介面,並通過動態代理的方式產生實現類,實現類中做負載均衡並調用其他服務。

1.1@FeignClient註解

只要是使用 OpenFeign 那麼這個註解是一定會使用到的,該註解的主要屬性如下:

  • url:可以手動指定 @FeignClient 調用的遠程服務地址,如果同時聲明 url 和 name 則以 url 為準,此時 name 僅作為該 FeignClient 的名稱而已;
  • name:指定當前 FeignClient 的名稱,如果項目使用了 Ribbon,那麼 name 屬性會作為微服務的名稱,用於服務的發現
  • value:實際上和 name 是用一個屬性,因為這兩個屬性互相使用了別名,使用的時候兩者選其一即可;
  • path:定義當前 FeignClient 的統一首碼,即表示所有調用的遠程服務都會走這個 path 聲明的 http 首碼;
  • configuration:Feign 的配置類,可以自定義 Feign 的 Encoder、Decoder、LogLevel、Contract 等;
  • fallback:定義容錯的處理類,當調用遠程介面失敗或超時,會調用對應介面的容錯邏輯,fallback 指定的類必須實現 @FeignClient 標記的介面。

簡單示例如下:

@FeignClient(url = "https://xxx.abcdef.com", name = "SubmitTaskClient", 
             configuration = OpenFeignFormConfig.class, fallback = HystrixFallbackConfig.class)
public interface SubmitTaskClient {

    /**
     * 調用遠程介面實現,入參為 json 字元串
     * @param paramJsonStr
     * @param header
     * @return
     */
    @PostMapping
    String submitNormalTask(@RequestBody String paramJsonStr, @RequestHeader Map<String, String> header);

    /**
     * 調用遠程介面實現,入參為 map 的表單形式
     * @param map
     * @return
     */
    @PostMapping(value = "/task/create", headers = {"content-type=application/x-www-form-urlencoded"})
    String submitTransTask(Map<String, ?> map);

}

1.2註意事項

在遠程服務調用一般存在兩種情況:

  1. 遠程服務在註冊中心

    如果遠程服務的提供方已經註冊到註冊中心,那麼 name 或者 value 的值為:註冊中心的服務名稱,且必須為所有客戶端指定一個 name 或者 value。

    @FeignClient(name = "SubmitTaskService", configuration = OpenFeignFormConfig.class, fallback = HystrixFallbackConfig.class)
    
  2. 單獨的遠程 http 介面

    此處 name 的值為當前 feignClient 客戶端的名稱,指定的 url 則為遠程服務的地址。

    @FeignClient(url = "https://xxx.abcdef.com", name = "SubmitTaskClient", configuration = OpenFeignFormConfig.class)
    

    以上兩種方式都能正常進行遠程服務調用。name 可以為註冊中心的服務名稱,同時有 url 屬性時,name 就與註冊中心服務名稱無關。


二、常見的Http API

OpenFeign 本質上還是使用 http 請求完成服務的調用,其實使用以下的這些 Http API 經過適當的改造後,也可以達到效果。

2.1Apache

在後端領域,出現比較早而且使用仍然很廣泛的 HTTP 客戶端框架非 Apache HttpClien 莫屬了,目前大量項目和公司仍在採用該框架。

Apache HttpClient 有著不錯的性能、豐富的功能以及強大的自定義實現等特色。但是隨著技術的發展和設計理念的改變,Apache HttpClient 顯的有些落伍了。

個人認為其最不受歡迎的點主要在於 API 的設計過於臃腫,大量的配置需要手動聲明,當見過了更多好的的 Http API 後你可能就會不太想繼續用了。當然公司框架正在使用 Apache HttpClient 的情況下也無可厚非,雖然複雜點,但用還是可以用的。

引入 pom 依賴:

        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

POST 請求示例如下:

    public String apacheHttpClientPost(String url, String params) throws Exception {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json");
        String charSet = "UTF-8";
        StringEntity entity = new StringEntity(params, charSet);
        httpPost.setEntity(entity);
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            StatusLine status = response.getStatusLine();
            int state = status.getStatusCode();
            if (state == 200) {
                HttpEntity responseEntity = response.getEntity();
                return EntityUtils.toString(responseEntity);
            }
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

2.2Okhttp

OkHttp3 是 OkHttp 發展到版本3.0之後的名字。在 maven 中央倉庫搜索 okhttp,可以看到 3.0 之後的版本統一稱為 OkHttp3。

OKHttp3 是一個當前主流的網路請求的開源框架,由 Square 公司開發,目標是用於替代 HttpUrlConnection 和 Apache HttpClient。

        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.1</version>
        </dependency>

POST 請求示例如下:

	public String okHttpPostMethod(String url,String body,  OkHttpClient okHttpClient) throws IOException {
        MediaType JSON_TYPE = MediaType.parse("application/json");
        Request request = new Request.Builder()
                .url(url).post(RequestBody.create(JSON_TYPE, body)).addHeader("Content-Type", "application/json")
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
        assert response != null;
        if (response.isSuccessful()) {
            return response.body() == null ? "" : response.body().string();
        }
        return null;
    }

對於需要單獨處理 POST、GET 等請求的情況來說,OkHttp3 是很適合的。

但是對於一些通用請求,比如在一個通用方法的參數里只需要傳入 Method 枚舉(POST、GET 等)就可以實現對應類型的請求,Hutool 和 RestTemplate 可能更為合適。

2.3Hutool

Hutool 中的工具方法來自每個用戶的精雕細琢,它涵蓋了 Java 開發底層代碼中的方方面面,是國內 Java 開發工具類庫的集大成者,很多公司的很多項目都在用。

其中 Hutool 的 http 部分是基於 HttpUrlConnection 的 Http 客戶端封裝,大致發起調用的步驟:首先構建一個http請求,包括請求的地址、請求方式、請求頭、請求參數等信息,然後執行請求返回一個 http 響應類,最後通過這個相應類可以獲取響應的主體、是否請求成功等信息。

但遺憾的是,團隊里也有比較明確的安全規定:不允許在項目中引入 Hutool 依賴包。

引入 pom 依賴:

        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.8</version>
        </dependency>

創建通用請求的示例如下:

    public String huToolMethod(String url, HttpMethod httpMethod, RequestBody body) {
        Map<String, String> headers = new HashMap<>();
        headers.put(HttpHeaders.CONTENT_TYPE, "application/json;charset=utf-8");
        // 創建通用請求, 可以涵蓋所有常見的 HTTP 方法, 同時放入 url
        HttpRequest request = HttpUtil.createRequest(Method.valueOf(httpMethod.name()), url);
        // 放入請求的 header 和 body
        HttpResponse response = request.addHeaders(headers).body(JSON.toJSONString(body)).execute();
        return response.body();
    }

三、RestTemplate

RestTemplate 是 Spring 框架用來訪問 RESTFUL 服務的客戶端模板類,主要功能有:

1、發起 HTTP 請求,包括 RESTful 風格的 GET,POST,PUT,DELETE 等常見方法;

2、自動將響應結果映射為 Java 對象,不用手動解析 JSON 或 XML。

3、自定義設置請求頭、消息轉碼、Cookie 等功能。

4、對不同的輸入/輸出類型提供對應的方法,如字元串、對象、多部分等。

5、同時還支持遠程調用,不受同源策略限制。

引入 pom 依賴:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

配置類:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(10000);
        factory.setReadTimeout(10000);
        return factory;
    }
}

3.1詳解.execute()

.execute() 是 RestTemplate 中最常見的關於執行 HTTP 請求的方法,它允許開發人員高度定製 HTTP 請求。

先來給一段示例:

    public String restTemplateExecuteMethod(String url, String token, Object body, HttpMethodName method){
        HttpHeaders httpHeaders = new HttpHeaders();
        // headers:HttpHeaders 類型,包括所有頭信息
        httpHeaders.add("Authorization", token);
        httpHeaders.add("Content-Type", "application/json;charset=utf-8");
        // body:請求體,可以是任何對象,也可以是 null
        HttpEntity<Object> httpEntity = new HttpEntity<>(JSON.toJSONString(body), httpHeaders);
        RequestCallback requestCallback = restTemplate.httpEntityCallback(httpEntity, Object.class);
        ResponseExtractor<ResponseEntity<Object>> responseExtractor = restTemplate.responseEntityExtractor(Object.class);
        // 發送請求,method.name() 表示傳入的方法,包括 GET、POST、DELETE 等
        ResponseEntity<Object> entity = restTemplate.execute(url, HttpMethod.valueOf(method.name()), requestCallback, responseExtractor);
        // 直接返回 body
        Assert.notNull(entity, "返回體為空!");
        log.info("---返回的內容:{}---", JSON.toJSONString(entity.getBody()));
        return JSON.toJSONString(entity.getBody());
    }

下麵是一些對象的介紹:

  • HttpEntity 對象

    它主要有兩個作用:

    1、表示 HTTP 請求:當表示 HTTP 請求時,HttpEntity 有兩個主要組成部分:請求頭和請求體。

    2、表示 HTTP 響應:當表示 HTTP 響應時,有三個部分:狀態碼、響應頭和響應體。

    其中的參數:

    • headers:HttpHeaders 類型,包括所有頭信息;
    • body:請求或響應體,可以是任何對象,也可以是null;
    • statusCode:HttpStatus 類型,只有在表示響應時才有效。
  • RequestCallback 對象

    RequestCallback 是 RestTemplate中用來定製HTTP請求的一個介面,可以設置請求頭、請求體、查詢字元串參數。

    Callback介面只有一個方法:

    void doWithRequest(ClientHttpRequest request) throws IOException
    

四、文章小結

文章的最後,我選擇了 okhttp3 和 RestTemplate 來進行 OpenFeign 的替換工作:okhttp3 處理單個 POST/GET 等請求,使用.execute() 處理通用 HTTP 請求。

那麼如何使用 Http API 代替 OpenFeign 進行遠程服務調用的分享到這裡就結束了,如有不足和錯誤,還請大家指正。或者你有其它想說的,也歡迎大家在評論區交流!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、海豚調度介紹 Apache DolphinScheduler 是一個分散式易擴展的可視化DAG工作流任務調度開源系統。適用於企業級場景,提供了一個可視化操作任務、工作流和全生命周期數據處理過程的解決方案。 Apache DolphinScheduler 旨在解決複雜的大數據任務依賴關係,併為應用 ...
  • 下麵介紹三種用於進行排序的專用視窗函數: 1、RANK() 在計算排序時,若存在相同位次,會跳過之後的位次。 例如,有3條排在第1位時,排序為:1,1,1,4······ 2、DENSE_RANK() 這就是題目中所用到的函數,在計算排序時,若存在相同位次,不會跳過之後的位次。 例如,有3條排在第1 ...
  • 在近日舉辦的鴻蒙生態千帆啟航儀式上,華為常務董事、終端BG CEO餘承東表示,鴻蒙生態設備已經增至8億 ,將打開萬億產業新藍海。 在本次論壇上,華為宣佈HarmonyOS NEXT鴻蒙星河版(開發者預覽版)已面向開發者開放申請。該版本,能夠實現原生精緻、原生易用、原生流暢、原生安全、原生智能、原生互 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 依賴管理解決了在軟體開發過程中管理和協調各種依賴項的問題,簡化了開發流程,提高了項目的可靠性、可維護性和可重覆性。它們幫助開發人員更高效地管理項目的依賴關係,減少了潛在的錯誤和衝突,並提供了更好的開發體驗。 常用的依賴管理 在 JavaS ...
  • 最近,有群里在群里發了這麼一個非常有意思的卡片 Hover 動效,來源於此網站 -- key-drop,效果如下: 非常有意思酷炫的效果。而本文,我們不會完全還原此效果,而是基於此效果,嘗試去製作這麼一個類似的卡片交互效果: 該效果的幾個核心點: 卡片的 3D 旋轉跟隨滑鼠移動效果 如何讓卡片在 H ...
  • 一、定義 定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類不改變一個演算法的結構即可重定義該演算法的特定步驟。模板方法是一種類行為型模式 二、描述 模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,包含以下兩個角色: 1、AbstractClass(抽象類):在抽象 ...
  • 本文在原文基礎上有刪減,原文參考泛型、Trait 和生命周期。 目錄泛型數據類型在函數定義中使用泛型結構體定義中的泛型枚舉定義中的泛型方法定義中的泛型泛型代碼的性能Trait:定義共同行為定義 trait為類型實現 trait預設實現trait 作為參數Trait Bound 語法通過 + 指定多個 ...
  • 一、pom.xml需要引入的依賴二、項目開啟熔斷器開關 2.1 註解方式 2.2 xml方式三、依賴類缺失問題四、版本匹配安全檢查問題五、測試驗證六、結論 一、pom.xml需要引入的依賴 pom.xml <!-- springboot升級到2.6.7,同樣適用於2.7.0,2.7.18等 --> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...