跟我學SpringCloud | 第二十章:Spring Cloud 之 okhttp
- 2019 年 10 月 3 日
- 筆記
1. 什麼是 okhttp ?
okhttp 是由 square 公司開源的一個 http 客戶端。在 Java 平台上,Java 標準庫提供了 HttpURLConnection 類來支援 HTTP 通訊。不過 HttpURLConnection 本身的 API 不夠友好,所提供的功能也有限。大部分 Java 程式都選擇使用 Apache 的開源項目 HttpClient 作為 HTTP 客戶端。Apache HttpClient 庫的功能強大,使用率也很高。
2. 為什麼要使用 okhttp ?
okhttp 的設計初衷就是簡單和高效,這也是我們選擇它的重要原因之一。它的優勢如下:
- 支援 HTTP/2 協議。
- 允許連接到同一個主機地址的所有請求,提高請求效率。
- 共享Socket,減少對伺服器的請求次數。
- 通過連接池,減少了請求延遲。
- 快取響應數據來減少重複的網路請求。
- 減少了對數據流量的消耗。
- 自動處理GZip壓縮。
3. 實戰目標
- Feign 中使用 okhttp 替代 httpclient
- Zuul 中使用 okhttp 替代 httpclient
4. 在 Feign 中使用 okhttp
首先介紹一下工程結構,本演示工程包含 provider-server、consumer-server、eureka-server 和 zuul-server 。
4.1 consumer-server 依賴 pom.xml 如下:
程式碼清單:chapter19/consumer-server/pom.xml
***
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> </dependency> </dependencies>
feign-okhttp
這裡無需指定版本,目前引入的feign-okhttp
版本為 10.2.3 ,而okhttp
的版本為 3.8.1 ,如圖:
4.2 配置文件 application.yml
程式碼清單:chapter19/consumer-server/src/main/resources/application.yml
***
feign: httpclient: enabled: false okhttp: enabled: true
- 在配置文件中需關閉 feign 對 httpclient 的使用並開啟 okhttp 。
4.3 配置類 OkHttpConfig.java
程式碼清單:chapter19/consumer-server/src/main/java/com/springcloud/consumerserver/config/OkHttpConfig.java
***
@Configuration @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) public class OkHttpConfig { @Bean public OkHttpClient okHttpClient(){ return new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .connectionPool(new ConnectionPool(10 , 5L, TimeUnit.MINUTES)) .addInterceptor(new OkHttpLogInterceptor()) .build(); } }
- 在配置類中將
OkHttpClient
注入 Spring 的容器中,這裡我們指定了連接池的大小,最大保持連接數為 10 ,並且在 5 分鐘不活動之後被清除。 - 筆者這裡配置了一個 okhttp 的日誌攔截器。
4.4 日誌攔截器 OkHttpLogInterceptor.java
程式碼清單:
***
@Slf4j public class OkHttpLogInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { log.info("OkHttpUrl : " + chain.request().url()); return chain.proceed(chain.request()); } }
- 這裡實現的介面是
okhttp3.Interceptor
,並不是 Spring Boot 中的 Interceptor。 - 筆者這裡僅簡單列印了 okhttp 請求的路徑,如果有業務校驗許可權等需求可以放在攔截器中實現。
遠程 Feign 調用程式碼略過,有需要的讀者可以訪問 Github 倉庫獲取。
5. 在 Zuul 中使用 okhttp
5.1 pom.xml 加入 okhttp 依賴
程式碼清單:chapter19/zuul-server/pom.xml
***
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> </dependency>
5.2 配置文件開啟 okhttp
程式碼清單:chapter19/zuul-server/src/main/resources/application.yml
***
ribbon: http: client: enabled: false okhttp: enabled: true
- 因為 Zuul 的負載均衡實現是通過 Ribbon 實現的,所以 Http 客戶端的配置自然也是對 Ribbon 組件的配置。
6. 測試
我們修改 idea 啟動配置,分別在 8000 和 8001 埠啟動 provider-server ,並且順次啟動其餘工程,打開瀏覽器訪問鏈接:http://localhost:8080/consumer/hello ,多次刷新,可以看到 Hello Spring Cloud! Port : 8000
和 Hello Spring Cloud! Port : 8001
交替書出現,可以證明負載均衡已經成功,可以查看 consumer-server 的日誌,如下:
2019-09-23 23:15:27.097 INFO 10536 --- [nio-9000-exec-5] c.s.c.intercepter.OkHttpLogInterceptor : OkHttpUrl : http://host.docker.internal:8001/hello 2019-09-23 23:15:27.593 INFO 10536 --- [nio-9000-exec-6] c.s.c.intercepter.OkHttpLogInterceptor : OkHttpUrl : http://host.docker.internal:8000/hello 2019-09-23 23:15:27.942 INFO 10536 --- [nio-9000-exec-7] c.s.c.intercepter.OkHttpLogInterceptor : OkHttpUrl : http://host.docker.internal:8001/hello 2019-09-23 23:15:28.251 INFO 10536 --- [nio-9000-exec-9] c.s.c.intercepter.OkHttpLogInterceptor : OkHttpUrl : http://host.docker.internal:8000/hello 2019-09-23 23:15:47.877 INFO 10536 --- [nio-9000-exec-8] c.s.c.intercepter.OkHttpLogInterceptor : OkHttpUrl : http://host.docker.internal:8001/hello
可以看到我們剛才自定義的日誌正常列印,證明現在訪問確實是通過 okhttp 來進行訪問的。