HttpClient、OkHttp、RestTemplate、WebClient的基本使用

摘要

  • 本文内容基于org.apache.httpcomponents:httpclient:4.5.12,com.squareup.okhttp3:okhttp:4.5.0,springboot:2.2.6.RELEASE,spring-boot-starter-webflux:2.2.6.RELEASE
  • 工具类,实现get/post[参数,json,输入流,文件,gzip]等方法
  • 提供了测试用例及服务端demo
  • github:https://github.com/hanqunfeng/springbootchapter/tree/master/chapter26

HttpClientUtil

package org.example;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * <p>HttpClient工具类</p>
 * Created by hanqf on 2020/4/18 14:54.
 */

@Slf4j
public class HttpClientUtil {
    /**
     * 配置信息
     */
    private static final RequestConfig requestConfig = RequestConfig.custom()
            // 设置连接超时时间(单位毫秒)
            .setConnectTimeout(5000)
            // 设置请求超时时间(单位毫秒)
            .setConnectionRequestTimeout(5000)
            // socket读写超时时间(单位毫秒)
            .setSocketTimeout(5000)
            // 设置是否允许重定向(默认为true)
            .setRedirectsEnabled(true)
            //是否启用内容压缩,默认true
            .setContentCompressionEnabled(true)
            .build();
    /**
     * 获得Http客户端
     */
    private static final CloseableHttpClient HTTP_CLIENT = HttpClientBuilder.create()
            .setRetryHandler(new DefaultHttpRequestRetryHandler()) //失败重试,默认3次
            .build();

    /**
     * 异步Http客户端
     */
    private static final CloseableHttpAsyncClient HTTP_ASYNC_CLIENT = HttpAsyncClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .build();


    /**
     * <p>异步请求</p>
     *
     * @param httpRequestBase
     * @author hanqf
     * 2020/4/22 21:16
     */
    private static void executeAsync(HttpRequestBase httpRequestBase) {
        HTTP_ASYNC_CLIENT.start();
        HTTP_ASYNC_CLIENT.execute(httpRequestBase, new FutureCallback<HttpResponse>() {
            @SneakyThrows
            @Override
            public void completed(HttpResponse httpResponse) {
                log.info(" callback thread id is : " + Thread.currentThread().getId());
                log.info(httpRequestBase.getRequestLine() + "->" + httpResponse.getStatusLine());

                StringBuffer stringBuffer = new StringBuffer();
                for (Header header : httpRequestBase.getAllHeaders()) {
                    stringBuffer.append(header.toString()).append(",");
                }
                log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


                String responseResult = null;
                HttpEntity responseEntity = httpResponse.getEntity();
                log.debug("响应状态为:" + httpResponse.getStatusLine());
                if (responseEntity != null) {
                    responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
                    log.info("响应内容为:" + responseResult);

                }

                stringBuffer = new StringBuffer();
                for (Header header : httpResponse.getAllHeaders()) {
                    stringBuffer.append(header.toString()).append(",");
                }
                log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));


            }

            @Override
            public void failed(Exception e) {
                log.info(" callback thread id is : " + Thread.currentThread().getId());
                log.info("Get responseResult:", e);
                e.printStackTrace();
            }

            @Override
            public void cancelled() {
                log.info(httpRequestBase.getRequestLine() + " cancelled");
            }
        });
    }


    /**
     * <p>请求的执行方法,需要提前封装好httpRequestBase对象,如请求url和请求参数</p>
     *
     * @param httpRequestBase
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 22:08
     */
    private static String execute(HttpRequestBase httpRequestBase) {
        log.info(String.format("请求地址: [%s]", httpRequestBase.getURI().toString()));
        log.info(String.format("请求类型: [%s]", httpRequestBase.getMethod()));

        StringBuffer stringBuffer = new StringBuffer();
        for (Header header : httpRequestBase.getAllHeaders()) {
            stringBuffer.append(header.toString()).append(",");
        }
        log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


        log.info(String.format("请求参数: [%s]", httpRequestBase.getURI().getQuery()));

        String responseResult = null;
        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 将上面的配置信息 运用到这个Get请求里
            httpRequestBase.setConfig(requestConfig);
            long t1 = System.nanoTime();//请求发起的时间
            response = HTTP_CLIENT.execute(httpRequestBase);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            log.debug("响应状态为:" + response.getStatusLine());
            long t2 = System.nanoTime();//收到响应的时间
            if (responseEntity != null) {

                responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);

                log.debug("响应内容为:" + responseResult);

            }

            stringBuffer = new StringBuffer();
            for (Header header : response.getAllHeaders()) {
                stringBuffer.append(header.toString()).append(",");
            }
            log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

            log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return responseResult;

    }

    /**
     * <p>请求的执行方法,需要提前封装好httpRequestBase对象,如请求url和请求参数</p>
     *
     * @param httpRequestBase
     * @return byte[]
     * @author hanqf
     * 2020/4/29 13:33
     */
    private static byte[] executeBytes(HttpRequestBase httpRequestBase) {
        log.info(String.format("请求地址: [%s]", httpRequestBase.getURI().toString()));
        log.info(String.format("请求类型: [%s]", httpRequestBase.getMethod()));
        StringBuffer stringBuffer = new StringBuffer();
        for (Header header : httpRequestBase.getAllHeaders()) {
            stringBuffer.append(header.toString()).append(",");
        }
        log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


        log.info(String.format("请求参数: [%s]", httpRequestBase.getURI().getQuery()));

        byte[] bytes = null;
        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 将上面的配置信息 运用到这个Get请求里
            httpRequestBase.setConfig(requestConfig);
            long t1 = System.nanoTime();//请求发起的时间
            response = HTTP_CLIENT.execute(httpRequestBase);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            log.debug("响应状态为:" + response.getStatusLine());
            long t2 = System.nanoTime();//收到响应的时间
            if (responseEntity != null) {
                bytes = EntityUtils.toByteArray(responseEntity);

                //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
                Header responseHeader = response.getFirstHeader("Content-Encoding");
                if (responseHeader != null && responseHeader.getValue().contains("gzip")) {
                    GZIPInputStream gzipInputStream = null;
                    ByteArrayOutputStream out = null;
                    try {
                        gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                        out = new ByteArrayOutputStream();
                        byte[] buffer = new byte[1024];
                        int offset = -1;
                        while ((offset = gzipInputStream.read(buffer)) != -1) {
                            out.write(buffer, 0, offset);
                        }
                        bytes = out.toByteArray();

                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            gzipInputStream.close();
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //判断是否需要解压,即服务器返回是否经过了gzip压缩--end

                log.debug("响应byte长度:" + bytes.length);
            }

            stringBuffer = new StringBuffer();
            for (Header header : response.getAllHeaders()) {
                stringBuffer.append(header.toString()).append(",");
            }
            log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

            log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return bytes;

    }

    /**
     * <p>get请求</p>
     *
     * @param url 请求地址
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 15:57
     */
    public static String get(String url) {
        return get(url, new HashMap<>());
    }

    /**
     * <p>get请求</p>
     *
     * @param url 请求地址
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 15:49
     */
    public static String get(String url, Map<String, Object> params) {
        HttpGet httpGet = null;
        List<NameValuePair> list = new ArrayList<>();
        for (String key : params.keySet()) {
            list.add(new BasicNameValuePair(key, params.get(key).toString()));
        }

        // 由客户端执行(发送)Get请求
        try {
            URI uri = new URIBuilder(url).addParameters(list).build();
            // 创建Get请求
            httpGet = new HttpGet(uri);

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }
        return execute(httpGet);
    }

    /**
     * <p>get请求,返回字节数组</p>
     *
     * @param url
     * @param params
     * @return byte[]
     * @author hanqf
     * 2020/4/29 13:35
     */
    public static byte[] getBytes(String url, Map<String, Object> params) {
        HttpGet httpGet = null;
        List<NameValuePair> list = new ArrayList<>();
        for (String key : params.keySet()) {
            list.add(new BasicNameValuePair(key, params.get(key).toString()));
        }

        // 由客户端执行(发送)Get请求
        try {
            URI uri = new URIBuilder(url).addParameters(list).build();
            // 创建Get请求
            httpGet = new HttpGet(uri);

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }
        return executeBytes(httpGet);
    }

    /**
     * <p>post请求</p>
     *
     * @param url 请求地址
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 15:54
     */
    public static String post(String url) {
        return post(url, new HashMap<>());
    }

    /**
     * <p>post请求</p>
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 15:50
     */
    public static String post(String url, Map<String, Object> params) {
        HttpPost httpPost = null;
        List<NameValuePair> list = new ArrayList<>();
        for (String key : params.keySet()) {
            list.add(new BasicNameValuePair(key, params.get(key).toString()));
        }

        try {
            URI uri = new URIBuilder(url).addParameters(list).build();
            httpPost = new HttpPost(uri);
        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }

        return execute(httpPost);
    }

    /**
     * <p>post请求,返回字节数组</p>
     *
     * @param url
     * @param params
     * @return byte[]
     * @author hanqf
     * 2020/4/29 13:35
     */
    public static byte[] postBytes(String url, Map<String, Object> params) {
        HttpPost httpPost = null;
        List<NameValuePair> list = new ArrayList<>();
        for (String key : params.keySet()) {
            list.add(new BasicNameValuePair(key, params.get(key).toString()));
        }

        try {
            URI uri = new URIBuilder(url).addParameters(list).build();
            httpPost = new HttpPost(uri);
        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }

        return executeBytes(httpPost);
    }

    /**
     * <p>post请求,请求体为json</p>
     *
     * @param url  请求地址
     * @param json 请求json
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 16:02
     */
    public static String postJson(String url, String json) {
        return postJson(url, json, false);
    }

    /**
     * <p>post请求,请求体为json</p>
     *
     * @param url  请求地址
     * @param json 请求json
     * @param gzip 是否开启gzip压缩
     * @return java.lang.String 响应结果
     * @author hanqf
     * 2020/4/18 16:02
     */
    public static String postJson(String url, String json, boolean gzip) {
        HttpPost httpPost = null;
        try {
            URI uri = new URIBuilder(url).build();
            httpPost = new HttpPost(uri);

            // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中

            httpPost.setHeader("Content-Type", "application/json;charset=utf8");

            if (gzip) {
                httpPost.setHeader("Content-Encoding", "gzip");
                ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
                originalContent.write(json.getBytes(StandardCharsets.UTF_8));
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
                originalContent.writeTo(gzipOut);
                gzipOut.finish();
                httpPost.setEntity(new ByteArrayEntity(baos
                        .toByteArray(), ContentType.create("text/plain", "utf-8")));
            } else {
                StringEntity entity = new StringEntity(json, "UTF-8");
                httpPost.setEntity(entity);

            }

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }
        return execute(httpPost);
    }

    /**
     * <p>post请求,请求参数中有中文的话可以使用这个请求</p>
     *
     * @param url    请求地址
     * @param params 请求参数,只可以为中文
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 16:30
     */
    public static String postForm(String url, Map<String, Object> params) {
        HttpPost httpPost = null;
        List<NameValuePair> list = new ArrayList<>();
        for (String key : params.keySet()) {
            list.add(new BasicNameValuePair(key, params.get(key).toString()));
        }

        try {
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, StandardCharsets.UTF_8);
            URI uri = new URIBuilder(url).build();
            httpPost = new HttpPost(uri);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.setEntity(urlEncodedFormEntity);


        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }

        return execute(httpPost);
    }

    /**
     * <p>post请求,输入流</p>
     *
     * @param url   请求地址
     * @param bytes 请求输入流
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 16:37
     */
    public static String postInputBytes(String url, byte[] bytes) {
        return postInputBytes(url, bytes, false);
    }

    /**
     * <p>post请求,输入流</p>
     *
     * @param url   请求地址
     * @param bytes 请求输入流
     * @param gzip  是否开启gzip压缩
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 16:37
     */
    public static String postInputBytes(String url, byte[] bytes, boolean gzip) {
        HttpPost httpPost = null;
        try {
            URI uri = new URIBuilder(url).build();
            httpPost = new HttpPost(uri);

            // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中
            if (gzip) {
                httpPost.setHeader("Content-Encoding", "gzip");
                ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
                originalContent.write(bytes);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
                originalContent.writeTo(gzipOut);
                gzipOut.finish();
                httpPost.setEntity(new ByteArrayEntity(baos
                        .toByteArray(), ContentType.create("text/plain", "utf-8")));
            } else {
                ByteArrayEntity entity = new ByteArrayEntity(bytes, ContentType.create("text/plain", "utf-8"));
                httpPost.setEntity(entity);
            }

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }

        return execute(httpPost);
    }

    /**
     * <p>post请求,流</p>
     *
     * @param url
     * @param is
     * @return java.lang.String
     * @author hanqf
     * 2020/4/21 22:24
     */
    public static String postInputStream(String url, InputStream is) {
        return postInputStream(url, is, false);
    }

    /**
     * <p>post请求,流</p>
     *
     * @param url
     * @param is
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/21 22:24
     */
    public static String postInputStream(String url, InputStream is, boolean gzip) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int ch;
        byte[] bytes = null;
        try {
            while ((ch = is.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, ch);
            }
            bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return postInputBytes(url, bytes, gzip);
    }

    /**
     * <p>post请求,传输附件</p>
     *
     * @param url   请求地址
     * @param files 文件列表
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 16:52
     */
    public static String postFile(String url, File[] files) {
        return postFile(url, new HashMap<>(), files);
    }

    /**
     * <p>post请求,传输附件</p>
     *
     * @param url    请求地址
     * @param params 其它参数
     * @param files  文件列表
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 16:50
     */
    public static String postFile(String url, Map<String, Object> params, File[] files) {
        HttpPost httpPost = null;
        try {
            URI uri = new URIBuilder(url).build();
            httpPost = new HttpPost(uri);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            String filesKey = "files";
            for (File file : files) {
                //multipartEntityBuilder.addPart(filesKey,new FileBody(file)); //与下面的语句作用相同
                //multipartEntityBuilder.addBinaryBody(filesKey, file);

                // 防止服务端收到的文件名乱码。 我们这里可以先将文件名URLEncode,然后服务端拿到文件名时在URLDecode。就能避免乱码问题。
                // 文件名其实是放在请求头的Content-Disposition里面进行传输的,如其值为form-data; name="files"; filename="头像.jpg"
                multipartEntityBuilder.addBinaryBody(filesKey, file, ContentType.DEFAULT_BINARY, URLEncoder.encode(file.getName(), "utf-8"));

            }

            // 其它参数(注:自定义contentType,设置UTF-8是为了防止服务端拿到的参数出现乱码)
            ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);
            for (String key : params.keySet()) {
                multipartEntityBuilder.addTextBody(key, params.get(key).toString(), contentType);
            }
            HttpEntity entity = multipartEntityBuilder.build();

            // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中
            httpPost.setEntity(entity);

        } catch (Exception e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }

        return execute(httpPost);
    }


}

OkHttpUtil

package org.example;


import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;
import org.jetbrains.annotations.NotNull;

import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;

/**
 * <p>OkHttp工具类</p>
 * Created by hanqf on 2020/4/18 21:54.
 */

@Slf4j
public class OkHttpUtil {

    /**
     * 获得OkHttpClient客户端
     */
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(5L, TimeUnit.SECONDS) //连接超时时间,5秒
            .readTimeout(5L, TimeUnit.SECONDS) //读超时时间,5秒
            .writeTimeout(5L, TimeUnit.SECONDS) //写超时时间,5秒
            .followRedirects(true) //设置是否允许重定向,默认true
            //注意拦截器的顺序
            .addInterceptor(new GzipRequestInterceptor()) //开启gzip压缩,支持对流或Json进行gzip压缩,服务端需要支持解压缩
            .addInterceptor(new RetryIntercepter()) //重试拦截器,默认3次
            .addInterceptor(new HeadersLoggingInterceper()) //header拦截器
            .build();


    /**
     * <p>异步调用</p>
     * @author hanqf
     * 2020/4/22 20:37
     * @param request
     */
    private static void executeAsync(Request request){
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                log.info("Get responseResult:", e);
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                String responseResult = null;
                if (response.isSuccessful()) {
                    responseResult = Objects.requireNonNull(response.body()).string();
                }
                Headers headers = response.headers();
                StringBuilder stringBuffer = new StringBuilder();
                for(int i=0;i<headers.size();i++){
                    stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
                }
                log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));
                log.info(String.format("响应结果:%s",responseResult));
            }
        });
    }

    /**
     * <p>请求的执行方法,需要提前封装好Request对象,如请求url和请求参数</p>
     *
     * @param request
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:47
     */
    private static String execute(Request request) {
        String responseResult = null;
        try {
            long t1 = System.nanoTime();//请求发起的时间
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                responseResult = Objects.requireNonNull(response.body()).string();
                //byte[] bytes = response.body().bytes();
                //responseResult = new String(bytes,"utf-8");
            }
            long t2 = System.nanoTime();//收到响应的时间
            Headers headers = response.headers();

            StringBuilder stringBuffer = new StringBuilder();
            for(int i=0;i<headers.size();i++){
                stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
            }
            log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

            log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));
        } catch (IOException e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }
        return responseResult;

    }

    private static byte[] executeBytes(Request request) {
        byte[] bytes = null;
        try {
            long t1 = System.nanoTime();//请求发起的时间
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                bytes = Objects.requireNonNull(response.body()).bytes();

                //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
                String responseHeader = response.header("Content-Encoding");
                if (responseHeader != null && responseHeader.contains("gzip")) {
                    GZIPInputStream gzipInputStream = null;
                    ByteArrayOutputStream out = null;
                    try {
                        gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                        out = new ByteArrayOutputStream();
                        byte[] buffer = new byte[1024];
                        int offset = -1;
                        while ((offset = gzipInputStream.read(buffer)) != -1) {
                            out.write(buffer, 0, offset);
                        }
                        bytes = out.toByteArray();

                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            gzipInputStream.close();
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //判断是否需要解压,即服务器返回是否经过了gzip压缩--end

            }
            long t2 = System.nanoTime();//收到响应的时间
            Headers headers = response.headers();
            StringBuilder stringBuffer = new StringBuilder();
            for(int i=0;i<headers.size();i++){
                stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
            }
            log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

            log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));
        } catch (IOException e) {
            log.info("Get responseResult:", e);
            e.printStackTrace();
        }
        return bytes;

    }

    /**
     * <p>get请求</p>
     *
     * @param url 请求url
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:48
     */
    public static String get(String url) {
        return get(url, new HashMap<>());

    }

    /**
     * <p>get请求</p>
     *
     * @param url
     * @param params
     * @return java.lang.String
     * @author hanqf
     * 2020/4/20 16:40
     */
    public static String get(String url, Map<String, Object> params) {
        if (params.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : params.keySet()) {
                stringBuffer.append(key).append("=").append(params.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }

        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        log.info(String.format("请求地址: [%s]", request.url()));
        if (params.size() > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(params);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }

        //executeAsync(request);
        return execute(request);

    }

    public static byte[] getBytes(String url, Map<String, Object> params) {
        if (params.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : params.keySet()) {
                stringBuffer.append(key).append("=").append(params.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }

        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        log.info(String.format("请求地址: [%s]", request.url()));
        if (params.size() > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(params);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }

        return executeBytes(request);

    }

    /**
     * <p>post请求</p>
     *
     * @param url 请求url
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:48
     */
    public static String post(String url) {
        return post(url, new HashMap<>());
    }

    /**
     * <p>post请求</p>
     * form请求
     *
     * @param url    请求url
     * @param params 请求参数
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:49
     */
    public static String post(String url, Map<String, Object> params) {
        //请求头会加入:application/x-www-form-urlencoded
        FormBody.Builder builder = new FormBody.Builder();
        for (String key : params.keySet()) {
            builder.add(key, params.get(key).toString());
        }
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        log.info(String.format("请求地址: [%s]", request.url()));
        if (params.size() > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(params);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }
        log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));

        return execute(request);

    }

    public static byte[] postBytes(String url, Map<String, Object> params) {
        //请求头会加入:application/x-www-form-urlencoded
        FormBody.Builder builder = new FormBody.Builder();
        for (String key : params.keySet()) {
            builder.add(key, params.get(key).toString());
        }
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        log.info(String.format("请求地址: [%s]", request.url()));
        if (params.size() > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(params);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }
        log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));

        return executeBytes(request);

    }


    /**
     * <p>post请求,json请求</p>
     *
     * @param url  请求url
     * @param json json数据
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:50
     */
    public static String post(String url, String json) {

        MediaType mediaType = MediaType.parse("application/json; charset=utf8");
        RequestBody requestBody = RequestBody.create(json, mediaType);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        log.info(String.format("请求地址: [%s]", request.url()));
        log.info(String.format("请求参数: %s", json));
        log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
        return execute(request);
    }

    /**
     * <p>post请求,字节流</p>
     *
     * @param url   请求url
     * @param bytes 字节数组
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:51
     */
    public static String post(String url, byte[] bytes) {

        MediaType mediaType = MediaType.parse("application/octet-stream");
        RequestBody requestBody = null;
        requestBody = RequestBody.create(bytes, mediaType);

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        log.info(String.format("请求地址: [%s]", request.url()));
        log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
        return execute(request);
    }

    /**
     * <p>post请求,字节流</p>
     *
     * @param url
     * @param is
     * @return java.lang.String
     * @author hanqf
     * 2020/4/21 22:45
     */
    public static String post(String url, InputStream is) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int ch;
        byte[] bytes = null;
        try {
            while ((ch = is.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, ch);
            }
            bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return post(url, bytes);
    }

    /**
     * <p>post请求,文件传输</p>
     *
     * @param url   请求url
     * @param files 文件列表
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:52
     */
    public static String post(String url, File[] files) {
        return post(url, new HashMap<>(), files);
    }

    /**
     * <p>post请求,文件传输</p>
     *
     * @param url    请求url
     * @param params 参数map
     * @param files  文件列表
     * @return java.lang.String
     * @author hanqf
     * 2020/4/18 23:52
     */
    public static String post(String url, Map<String, Object> params, File[] files) {

        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);
        int i = 1;
        try {
            String filesKey = "files";
            for (File file : files) {
                //URLEncoder.encode(file.getName(), "utf-8") //中文文件名使用encode,服务端使用decode解析
                builder.addFormDataPart(filesKey, URLEncoder.encode(file.getName(), "utf-8"),
                        RequestBody.create(file, MediaType.parse("multipart/form-data")));
                i++;
            }

            for (String key : params.keySet()) {
                builder.addFormDataPart(key, params.get(key).toString());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        RequestBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        log.info(String.format("请求地址: [%s]", request.url()));
        if (params != null && params.size() > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(params);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }
        if (files != null && files.length > 0) {
            JSONArray jArray = new JSONArray();
            jArray.add(files);
            log.info(String.format("请求参数: %s", jArray.toJSONString()));
        }
        log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
        return execute(request);
    }


    /**
     * This interceptor compresses the HTTP request body. Many webservers can't handle this!
     */
    private static class GzipRequestInterceptor implements Interceptor {
        @NotNull
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
                return chain.proceed(originalRequest);
            }

            MediaType mediaType = Objects.requireNonNull(originalRequest.body()).contentType();
            //对流和json开启压缩
            if (mediaType != null && ("application/octet-stream".equals(mediaType.toString()) || "application/json; charset=utf8".equals(mediaType.toString()))) {
                Request compressedRequest = originalRequest.newBuilder()
                        .header("Content-Encoding", "gzip")
                        .method(originalRequest.method(), gzip(originalRequest.body()))
                        .build();
                return chain.proceed(compressedRequest);
            }
            return chain.proceed(originalRequest);
        }


        private RequestBody gzip(final RequestBody body) {
            return new RequestBody() {
                @Override
                public MediaType contentType() {
                    return body.contentType();
                }

                @Override
                public long contentLength() {
                    return -1; // We don't know the compressed length in advance!
                }

                @Override
                public void writeTo(@NotNull BufferedSink sink) throws IOException {
                    BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                    body.writeTo(gzipSink);
                    gzipSink.close();
                }
            };
        }
    }

    /**
     * <p>重试拦截器</p>
     */
    private static class RetryIntercepter implements Interceptor {

        private int maxRetry = 3;//最大重试次数,默认3次
        private int retryNum = 0;

        public RetryIntercepter() {

        }

        public RetryIntercepter(int maxRetry) {
            this.maxRetry = maxRetry;
        }

        @NotNull
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            while (!response.isSuccessful() && retryNum < maxRetry) {
                retryNum++;
                response = chain.proceed(request);
            }
            return response;
        }
    }

    /**
     * <p>Headers拦截器</p>
     */
    private static class HeadersLoggingInterceper implements Interceptor {
        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
            Request request = chain.request();
            Headers headers = request.headers();
            StringBuilder stringBuffer = new StringBuilder();
            for(int i=0;i<headers.size();i++){
                stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
            }
            log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));
            return chain.proceed(request);
        }
    }
}

RestTemplateUtil

package org.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * <p>RestTemplate工具类</p>
 * Created by hanqf on 2020/4/22 16:54.
 */

@Slf4j
public class RestTemplateUtil {

    private static final SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    private static final RestTemplate restTemplate;

    static {
        factory.setReadTimeout(5000);//单位为ms
        factory.setConnectTimeout(5000);//单位为ms

        //拦截器
        List<ClientHttpRequestInterceptor> list = new ArrayList<>();
        list.add(new RetryIntercepter()); //重试拦截器
        list.add(new HeadersLoggingInterceper()); //header拦截器

        restTemplate = new RestTemplate(factory);
        restTemplate.setInterceptors(list);
    }

    public static String get(String url) {
        return get(url, new HashMap<>());
    }

    /**
     * <p>get请求</p>
     *
     * @param url
     * @param map
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 16:57
     */
    public static String get(String url, Map<String, Object> map) {
        if (map.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : map.keySet()) {
                stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }
        return restTemplate.getForObject(url, String.class);
    }

    public static byte[] getBytes(String url, Map<String, Object> map) {
        if (map.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : map.keySet()) {
                stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }
        //return restTemplate.getForObject(url, byte[].class);
        ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);
        byte[] bytes = exchange.getBody();


        //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
        List<String> strings = exchange.getHeaders().get("Content-Encoding");
        if (strings != null && strings.contains("gzip")) {
            GZIPInputStream gzipInputStream = null;
            ByteArrayOutputStream out = null;
            try {
                gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int offset = -1;
                while ((offset = gzipInputStream.read(buffer)) != -1) {
                    out.write(buffer, 0, offset);
                }
                bytes = out.toByteArray();

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    gzipInputStream.close();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //判断是否需要解压,即服务器返回是否经过了gzip压缩--end

        return bytes;

    }

    public static String post(String url) {
        return post(url, new HashMap<>());
    }

    /**
     * <p>post请求</p>
     *
     * @param url
     * @param params
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 16:59
     */
    public static String post(String url, Map<String, Object> params) {

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
        return restTemplate.postForObject(url, httpEntity, String.class);
    }

    public static byte[] postBytes(String url, Map<String, Object> params) {

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
        //byte[] bytes = restTemplate.postForObject(url, httpEntity, byte[].class);

        ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, byte[].class);
        byte[] bytes = exchange.getBody();


        //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
        List<String> strings = exchange.getHeaders().get("Content-Encoding");
        if (strings != null && strings.contains("gzip")) {
            GZIPInputStream gzipInputStream = null;
            ByteArrayOutputStream out = null;
            try {
                gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int offset = -1;
                while ((offset = gzipInputStream.read(buffer)) != -1) {
                    out.write(buffer, 0, offset);
                }
                bytes = out.toByteArray();

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    gzipInputStream.close();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //判断是否需要解压,即服务器返回是否经过了gzip压缩--end

        return bytes;
    }

    public static String postJson(String url, String json) {
        return postJson(url, json, false);
    }

    /**
     * <p>post请求json</p>
     *
     * @param url
     * @param json
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 17:04
     */
    public static String postJson(String url, String json, boolean gzip) {
        HttpHeaders headers = new HttpHeaders();


        if (gzip) {
            headers.setContentType(new MediaType("application", "octet-stream"));
            HttpEntity<byte[]> httpEntity = null;
            try {
                headers.add("Content-Encoding", "gzip");
                ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
                originalContent.write(json.getBytes(StandardCharsets.UTF_8));
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
                originalContent.writeTo(gzipOut);
                gzipOut.finish();
                httpEntity = new HttpEntity<>(baos.toByteArray(), headers);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return restTemplate.postForObject(url, httpEntity, String.class);
        } else {
            headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
            //headers.add("Content-Type", "application/json;charset=utf8");
            HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
            return restTemplate.postForObject(url, httpEntity, String.class);
        }
    }

    public static String postBytes(String url, byte[] bytes) {
        return postBytes(url, bytes, false);
    }

    /**
     * <p>post字节流</p>
     *
     * @param url
     * @param bytes
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 17:10
     */
    public static String postBytes(String url, byte[] bytes, boolean gzip) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType("application", "octet-stream"));
        HttpEntity<byte[]> httpEntity = null;
        if (gzip) {
            try {
                headers.add("Content-Encoding", "gzip");
                ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
                originalContent.write(bytes);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
                originalContent.writeTo(gzipOut);
                gzipOut.finish();
                httpEntity = new HttpEntity<>(baos.toByteArray(), headers);
            } catch (Exception e) {
                e.printStackTrace();
            }

        } else {
            httpEntity = new HttpEntity<>(bytes, headers);
        }
        return restTemplate.postForObject(url, httpEntity, String.class);

    }

    public static String postStream(String url, InputStream is) {
        return postStream(url, is, false);
    }

    /**
     * <p>post请求,流</p>
     *
     * @param url
     * @param is
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 17:12
     */
    public static String postStream(String url, InputStream is, boolean gzip) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int ch;
        byte[] bytes = null;
        try {
            while ((ch = is.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, ch);
            }
            bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return postBytes(url, bytes, gzip);

    }

    public static String postFiles(String url, File[] files) {
        return postFiles(url, new HashMap<>(), files);
    }

    /**
     * <p>post请求,传输文件</p>
     *
     * @param url
     * @param params
     * @param files
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 17:16
     */
    public static String postFiles(String url, Map<String, Object> params, File[] files) {

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }

        for (File file : files) {
            map.add("files", new FileSystemResource(file));
        }
        return restTemplate.postForObject(url, map, String.class);

    }

    /**
     * <p>重试拦截器</p>
     */
    private static class RetryIntercepter implements ClientHttpRequestInterceptor {

        private int maxRetry = 3;//最大重试次数,默认3次
        private int retryNum = 0;

        public RetryIntercepter() {

        }

        public RetryIntercepter(int maxRetry) {
            this.maxRetry = maxRetry;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
            ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
            if (!response.getStatusCode().equals(HttpStatus.OK) && retryNum < maxRetry) {
                retryNum++;
                response = clientHttpRequestExecution.execute(httpRequest, bytes);

            }
            return response;
        }
    }

    /**
     * <p>Headers拦截器</p>
     */
    private static class HeadersLoggingInterceper implements ClientHttpRequestInterceptor {

        @Override
        public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
            log.info(String.format("请求地址: %s", httpRequest.getURI()));
            log.info(String.format("请求头信息: %s", httpRequest.getHeaders()));
            ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
            log.info(String.format("响应头信息: %s", response.getHeaders()));
            return response;
        }
    }


}

WebClientUtil

package org.example;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.resources.LoopResources;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * <p></p>
 * Created by hanqf on 2020/4/23 21:33.
 */

@Slf4j
public class WebClientUtil {

    private static final ReactorResourceFactory factory = new ReactorResourceFactory();

    private static final WebClient webClient;

    static {
        factory.setUseGlobalResources(false);
        factory.setConnectionProvider(ConnectionProvider.create("httpClient", 50));
        factory.setLoopResources(LoopResources.create("httpClient", 50, true));

        Function<HttpClient, HttpClient> mapper = client ->
                client.tcpConfiguration(c ->
                        c.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                                .option(ChannelOption.TCP_NODELAY, true)
                                .doOnConnected(conn -> {
                                    conn.addHandlerLast(new ReadTimeoutHandler(10));
                                    conn.addHandlerLast(new WriteTimeoutHandler(10));
                                }));

        ClientHttpConnector connector =
                new ReactorClientHttpConnector(factory, mapper);

        webClient = WebClient.builder()
                .filter((request, next) -> {  //过滤器,3次重试,header打印
                    log.info(String.format("请求地址: %s", request.url()));
                    log.info(String.format("请求头信息: %s", request.headers()));
                    Mono<ClientResponse> exchange = next.exchange(request).retry(3);
                    ClientResponse clientResponse = exchange.block();
                    log.info(String.format("响应头信息: %s", clientResponse.headers().asHttpHeaders()));
                    return exchange;
                })
                .clientConnector(connector).build();

    }


    public static String get(String url) {
        return get(url, new HashMap<>());
    }

    /**
     * <p>get请求</p>
     *
     * @param url
     * @param map
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 14:44
     */
    public static String get(String url, Map<String, Object> map) {
        if (map.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : map.keySet()) {
                stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }
        String responseResult = null;
        Mono<String> mono = webClient.get().uri(url).retrieve().bodyToMono(String.class);
        responseResult = mono.block();

        return responseResult;
    }

    public static byte[] getBytes(String url, Map<String, Object> map) {
        if (map.size() > 0) {
            StringBuilder stringBuffer = new StringBuilder();
            stringBuffer.append(url);
            if (url.contains("?")) {
                stringBuffer.append("&");
            } else {
                stringBuffer.append("?");
            }
            for (String key : map.keySet()) {
                stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
            }
            url = stringBuffer.toString();
        }
        byte[] bytes = null;
        Mono<ClientResponse> exchange = webClient.get().uri(url).exchange();
        ClientResponse response = exchange.block();
        if (response.statusCode() == HttpStatus.OK) {
            Mono<byte[]> mono =  response.bodyToMono(byte[].class);
            bytes = mono.block();

            //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
            List<String> header = response.headers().header("Content-Encoding");
            if (header.contains("gzip")) {
                GZIPInputStream gzipInputStream = null;
                ByteArrayOutputStream out = null;
                try {
                    gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                    out = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int offset = -1;
                    while ((offset = gzipInputStream.read(buffer)) != -1) {
                        out.write(buffer, 0, offset);
                    }
                    bytes = out.toByteArray();

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        gzipInputStream.close();
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            //判断是否需要解压,即服务器返回是否经过了gzip压缩--end
        }

        return bytes;
    }

    public static String post(String url) {
        return post(url, new HashMap<>());
    }

    /**
     * <p>post请求</p>
     *
     * @param url
     * @param params
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 14:43
     */
    public static String post(String url, Map<String, Object> params) {
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }
        String responseResult = null;
        Mono<String> mono = webClient.post().uri(url).bodyValue(map).retrieve().bodyToMono(String.class);
        responseResult = mono.block();

        return responseResult;
    }

    public static byte[] postBytes(String url, Map<String, Object> params) {
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }
        byte[] bytes = null;
        Mono<ClientResponse> exchange = webClient.post().uri(url).bodyValue(map).exchange();
        ClientResponse response = exchange.block();
        if (response.statusCode() == HttpStatus.OK) {
            Mono<byte[]> mono =  response.bodyToMono(byte[].class);
            bytes = mono.block();

            //判断是否需要解压,即服务器返回是否经过了gzip压缩--start
            List<String> header = response.headers().header("Content-Encoding");
            if (header.contains("gzip")) {
                GZIPInputStream gzipInputStream = null;
                ByteArrayOutputStream out = null;
                try {
                    gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
                    out = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int offset;
                    while ((offset = gzipInputStream.read(buffer)) != -1) {
                        out.write(buffer, 0, offset);
                    }
                    bytes = out.toByteArray();

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        gzipInputStream.close();
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            //判断是否需要解压,即服务器返回是否经过了gzip压缩--end
        }


        return bytes;
    }

    /**
     * <p>post请求,form表单提交</p>
     *
     * @param url
     * @param params 这里要注意将参数值转为字符串,否则会报类型错误
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 14:43
     */
    public static String postForm(String url, Map<String, Object> params) {
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            for (String key : params.keySet()) {
                map.add(key, params.get(key).toString());
            }
        }
        String responseResult;
        Mono<String> mono = webClient.post().uri(url).contentType(MediaType.APPLICATION_FORM_URLENCODED).bodyValue(map).retrieve().bodyToMono(String.class);
        responseResult = mono.block();

        return responseResult;
    }


    public static String postJson(String url, String json) {
        return postJson(url, json, false);
    }

    /**
     * <p>post请求,json</p>
     *
     * @param url
     * @param json
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 15:45
     */
    public static String postJson(String url, String json, boolean gzip) {
        String responseResult;
        if (gzip) {
            byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
            return postBytes(url, bytes, true);
        } else {
            Mono<String> mono = webClient.post().uri(url).contentType(MediaType.APPLICATION_JSON).bodyValue(json).retrieve().bodyToMono(String.class);
            responseResult = mono.block();
        }

        return responseResult;
    }

    public static String postBytes(String url, byte[] bytes) {
        return postBytes(url, bytes, false);
    }

    /**
     * <p>post请求,字节流</p>
     *
     * @param url
     * @param bytes
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 15:45
     */
    public static String postBytes(String url, byte[] bytes, boolean gzip) {
        String responseResult;
        Mono<String> mono = null;
        WebClient.RequestBodySpec requestBodySpec = webClient.post().uri(url).contentType(MediaType.APPLICATION_OCTET_STREAM);
        if (gzip) {
            try {
                //headers.add("Content-Encoding", "gzip");
                ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
                originalContent.write(bytes);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
                originalContent.writeTo(gzipOut);
                gzipOut.finish();
                bytes = baos.toByteArray();
                mono = requestBodySpec.header("Content-Encoding", "gzip").bodyValue(bytes).retrieve().bodyToMono(String.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            mono = requestBodySpec.bodyValue(bytes).retrieve().bodyToMono(String.class);
        }
        responseResult = mono.block();

        return responseResult;

    }


    public static String postStream(String url, InputStream is) {
        return postStream(url, is, false);
    }

    /**
     * <p>post请求,流</p>
     *
     * @param url
     * @param is
     * @param gzip
     * @return java.lang.String
     * @author hanqf
     * 2020/4/22 17:12
     */
    public static String postStream(String url, InputStream is, boolean gzip) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int ch;
        byte[] bytes = null;
        try {
            while ((ch = is.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, ch);
            }
            bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return postBytes(url, bytes, gzip);

    }


    public static String postFiles(String url, File[] files) {
        return postFiles(url, new HashMap<>(), files);
    }

    /**
     * <p>post请求,文件</p>
     *
     * @param url
     * @param params
     * @param files
     * @return java.lang.String
     * @author hanqf
     * 2020/4/24 15:46
     */
    public static String postFiles(String url, Map<String, Object> params, File[] files) {
        String responseResult;
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        if (params != null && params.size() > 0) {
            map.setAll(params);
        }

        for (File file : files) {
            map.add("files", new FileSystemResource(file));
        }
        Mono<String> mono = webClient.post().uri(url).contentType(MediaType.MULTIPART_FORM_DATA).bodyValue(map).retrieve().bodyToMono(String.class);
        responseResult = mono.block();

        return responseResult;

    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容