spring cloud feign使用okhttp3


在Feign中,Client是一個非常重要的組件,Feign最終發送Request請求以及接收Response響應都是由Client組件來完成的。Client在Feign源碼中是一個接口,在默認情況下,Client的實現類是Client.Default。Client.Default是由HttpURLConnection來實現網絡請求的。另外,Client還支持HttpClient和OkHttp3來進行網絡請求。
HttpURLConnection沒有連接池,但是對每個地址會保持一個長連接,即利用HTTP的persistence connection 。我們可以用Apache的HTTP Client替換Feign原始的http client, 從而獲取連接池、超時時間等與性能息息相關的控制能力。
但是做Android的小伙伴早已經淘汰該庫了,就是因為其API數量過多過於繁重,使得我們很難在不破壞兼容性的情況下對它進行升級和擴展,因而團隊不願意去維護該庫.本章介紹的是由 Square 公司開發的OkHttp,是一個專注於性能和易用性的 HTTP 客戶端。

OkHttp的優點

okhttp 的設計初衷就是簡單和高效,這也是我們選擇它的重要原因之一。它的優勢如下:

  • 支持 HTTP/2 協議。
  • 允許連接到同一個主機地址的所有請求,提高請求效率。
  • 共享Socket,減少對服務器的請求次數。
  • 通過連接池,減少了請求延遲。
  • 緩存響應數據來減少重復的網絡請求。
  • 減少了對數據流量的消耗。
  • 自動處理GZip壓縮。

Feign使用Okhttp

maven

   <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.2.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>io.github.openfeign</groupId>
             <artifactId>feign-okhttp</artifactId>
             <version>10.1.0</version>
         </dependency>

配置文件

feign.httpclient.enabled=false
feign.okhttp.enabled=true

配置

package com.haier.uhome.iot.api.config;


import com.haier.uhome.iot.api.interceptors.OkHttpInterceptor;
import feign.Feign;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Slf4j
public class FeignClientConfig {

    private OkHttpClient okHttpClient;

    @Bean
    public OkHttpInterceptor okHttpInterceptor(){
        return new OkHttpInterceptor();
    }

    //注入okhttp
    @Bean
    public okhttp3.OkHttpClient okHttpClient(OkHttpClientFactory okHttpClientFactory,
                                             FeignHttpClientProperties httpClientProperties) {
        this.okHttpClient = okHttpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).connectTimeout(httpClientProperties.getConnectionTimeout(),TimeUnit.SECONDS)
                .followRedirects(httpClientProperties.isFollowRedirects())
                .addInterceptor(okHttpInterceptor())
                .build();
        return this.okHttpClient;
    }
}

配置攔截器

package com.haier.uhome.iot.api.interceptors;


import com.haier.uhome.iot.api.utils.CommonConstant;
import com.haier.uhome.iot.api.utils.ElasticsearchClient;
import com.haier.uhome.iot.core.util.Jackson;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.EOFException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;

@Slf4j
public class OkHttpInterceptor implements HandlerInterceptor, Interceptor {
    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Override
    public Response intercept(Chain chain) throws IOException {
        log.info("進入okhttp攔截器");
        //編碼設為UTF-8
        Charset charset = Charset.forName("UTF-8");
        try {
            HashMap esCmdLogMap = new HashMap();
            Request request = chain.request();
            HashMap requestMap = this.getRequestBody(request, charset);
            Response response = chain.proceed(request);
          if(request.url().toString().contains("manage/command")) {
              log.info(request.url().toString());
              HashMap responseMap = this.getResponseBody(response, charset);
              esCmdLogMap.put("requestUrl", request.url().toString());
              esCmdLogMap.put("request", requestMap);
              esCmdLogMap.put("deviceId", requestMap.get("deviceId"));
              esCmdLogMap.put("productCode", requestMap.get("productCode"));
              esCmdLogMap.put("response", responseMap);
              long startTime = System.currentTimeMillis();
//          LocalDateTime rightNow = LocalDateTime.now();
//          String createTime = rightNow.format(DateTimeFormatter.ISO_DATE);
              esCmdLogMap.put("cmdTime", startTime);
              elasticsearchClient.postRquestAsync(CommonConstant.INDEX_DEVICE_CMD, CommonConstant.TYPE_DEVICE_HIST, Jackson.object2JsonStr(esCmdLogMap));
          }
            return response;
        }catch (Exception e){
            throw  e;
        }
    }

    private HashMap getResponseBody(Response response,Charset charset) throws IOException {
        ResponseBody responseBody = response.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE);
        Buffer buffer = source.buffer();
        MediaType mediaType = responseBody.contentType();
        if(isPlaintext(buffer)){
            String result = buffer.clone().readString(mediaType.charset(charset));
            HashMap resultMap = Jackson.jsonStr2Object(result,HashMap.class);
            log.info("result:"+result);
            return resultMap;
        }
        return null;
    }

    private HashMap getRequestBody(Request request ,Charset charset) {
        RequestBody requestBody = request.body();
        Buffer reqbuffer = new Buffer();
        try {
            requestBody.writeTo(reqbuffer);
        } catch (IOException e) {
            e.printStackTrace();
        }

        MediaType contentType = requestBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(Charset.forName("UTF-8"));
        }
        //拿到request
        return Jackson.jsonStr2Object(reqbuffer.readString(charset),HashMap.class);
    }

    /**
     * Returns true if the body in question probably contains human readable text. Uses a small sample
     * of code points to detect unicode control characters commonly used in binary file signatures.
     */
    static boolean isPlaintext(Buffer buffer) throws EOFException {
        try {
            Buffer prefix = new Buffer();
            long byteCount = buffer.size() < 64 ? buffer.size() : 64;
            buffer.copyTo(prefix, 0, byteCount);
            for (int i = 0; i < 16; i++) {
                if (prefix.exhausted()) {
                    break;
                }
                int codePoint = prefix.readUtf8CodePoint();
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                    return false;
                }
            }
            return true;
        } catch (EOFException e) {
            return false; // Truncated UTF-8 sequence.
        }
    }

    private boolean bodyEncoded(Headers headers) {
        String contentEncoding = headers.get("Content-Encoding");
        return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM