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");
    }
}
定位问题原因* 根据原因思考问题解决方案* 实践验证方案有效性* 提交验证结果
原文地址:https://www.cnblogs.com/jimoliunian/p/14676009.html