OkHttpClientUtils

96 阅读3分钟

OkHttpClientUtils

import com.jd.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: 
 */
@Slf4j
public class OkHttpClientUtils {
    private static volatile OkHttpClientUtils mInstance;
    private OkHttpClient client;
    /**
     * json
     */
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json;charset=UTF-8");

    private OkHttpClientUtils(OkHttpClient okHttpClient) {
        this.client = okHttpClient;
    }

    /**
     * 获取默认OkHttpClient
     *
     * @return
     */
    private static OkHttpClient obtainDefaultOkHttpClient() {
        return new OkHttpClient.Builder()
                .addInterceptor(new LogInterceptor())
                .retryOnConnectionFailure(true)
                .connectTimeout(10, TimeUnit.SECONDS) //连接超时
                .readTimeout(10, TimeUnit.SECONDS) //读取超时
                .writeTimeout(10, TimeUnit.SECONDS)//写超时
                .build();
    }

    public static OkHttpClientUtils getInstance(){
        return getInstance(null);
    }
    /**
     * 获取 OkHttpClientUtils 实例
     */
    public static OkHttpClientUtils getInstance(OkHttpClient mOkHttpClient) {
        if (mInstance == null) {
            synchronized (OkHttpClientUtils.class) {
                if (mInstance == null) {
                    mInstance = Optional.ofNullable(mOkHttpClient).map(OkHttpClientUtils::new).orElseGet(() -> {
                        return new OkHttpClientUtils(obtainDefaultOkHttpClient());
                    });
                }
            }
        }
        return mInstance;
    }


    /**
     * 发送Get请求
     *
     * @param url     请求url
     * @param headers 请求头
     * @return
     */
    public Response doGet(String url, Map<String, String> headers) {
        log.info("HttpClientUtil doGet url: {}", url);
        Request request = new Request.Builder()
                .url(url)
                .get()
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http get method execute error", e);
        }
        return response;
    }

    /**
     * get 请求
     *
     * @param url     String
     * @param params  Map<String, Object>
     * @param headers Map<String, String>
     * @return Response
     */
    public Response doGet(String url, Map<String, Object> params, Map<String, String> headers) {
        if (CollectionUtils.isEmpty(params)) {
            return doGet(url, headers);
        }
        String urlWithParams = UriUtil.generateUrlWithParams(url, params);
        return doGet(urlWithParams, headers);
    }

    /**
     * 发送Post 请求
     *
     * @param url       请求地址
     * @param paramJson 参数
     * @param headers   请求头
     * @return
     */
    public Response doPost(String url, String paramJson, Map<String, String> headers) {
        RequestBody body = RequestBody.create(paramJson, MEDIA_TYPE_JSON);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http post method execute error", e);
        }
        return response;
    }


    /**
     * post请求 - 表单格式
     *
     * @param url      String
     * @param formData Map<String, String>
     * @return Response
     */
    public Response doPostByForm(String url, Map<String, String> formData, Map<String, String> headers) {
        log.info("HttpClientUtil doPost url: {} formData: {}", url, formData);
        FormBody.Builder builder = new FormBody.Builder();
        if (!CollectionUtils.isEmpty(formData)) {
            formData.forEach(builder::add);
        }
        FormBody formBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http post method execute error", e);
        }
        return response;
    }

    /**
     * put请求
     *
     * @param url       String
     * @param paramJson String
     * @param headers   Map<String, String>
     * @return Response
     */
    public Response doPut(String url, String paramJson, Map<String, String> headers) {
        log.info("HttpClientUtil doPut url: {} body: {}", url, paramJson);
        RequestBody body = RequestBody.create(paramJson, MEDIA_TYPE_JSON);
        Request request = new Request.Builder()
                .url(url)
                .put(body)
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http put method execute error", e);
        }
        return response;
    }

    /**
     * 删除
     *
     * @param url     String
     * @param headers Map<String, String>
     * @return Response
     */
    public Response doDelete(String url, String string, Map<String, String> headers) {
        log.info("HttpClientUtil doDelete url: {} body: {}", url, string);
        RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, string);
        Request request = new Request.Builder()
                .url(url)
                .delete(body)
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http delete method execute error", e);
        }
        return response;
    }

    /**
     * 删除
     *
     * @param url     String
     * @param headers Map<String, String>
     * @return Response
     */
    public Response doDelete(String url, Map<String, String> headers) {
        log.info("HttpClientUtil doDelete url: {}", url);
        Request request = new Request.Builder()
                .url(url)
                .delete()
                .headers(buildHeaders(headers))
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            log.error("http delete method execute error", e);
        }
        return response;
    }


    /**
     * 组装请求头
     *
     * @param headers Map<String, String>
     * @return Headers
     */
    private static Headers buildHeaders(Map<String, String> headers) {
        Headers.Builder builder = new Headers.Builder();
        if (Objects.isNull(headers) || headers.isEmpty()) {
            return builder.build();
        }
        headers.forEach(builder::add);
        return builder.build();
    }

    /**
     * 获取请求参数
     *
     * @param request
     * @return
     */
    public static String requestBodyToString(final RequestBody request) {
        try {
            final Buffer buffer = new Buffer();
            if (request != null) {
                request.writeTo(buffer);
            } else {
                return "";
            }
            return buffer.readUtf8();
        } catch (final IOException e) {
            return "";
        }
    }

    /**
     * 获取trace id
     *
     * @param headers Headers
     * @return String
     */
    private static String getTraceId(final Headers headers) {
        for (int i = 0, count = headers.size(); i < count; i++) {
            if ("TRACE-ID".equals(headers.name(i).toUpperCase())) {
                return headers.value(i);
            }
        }
        return "";
    }

    /**
     * 解析请求结果
     *
     * @param response Response
     * @return XbpResponse
     */
    public static String getBodyString(final Response response) {
        if (Objects.isNull(response)) {
            log.error("http response body is null");
            return null;
        }
        if (Objects.nonNull(response.body())) {
            try {
                BufferedSource source = response.body().source();
                source.request(Long.MAX_VALUE);
                Buffer buffer = source.buffer();
                return buffer.clone().readString(StandardCharsets.UTF_8);
            } catch (IOException e) {
                log.error("http response body string error", e);
                return null;
            }
        }
        return null;
    }

    /**
     * 日志记录
     */
    private static class LogInterceptor implements Interceptor {

        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
            Request request = chain.request();
            HttpUrl url = request.url();
            RequestBody body = request.body();
            String requestBodyString = requestBodyToString(body);
            Response response = null;
            try {
                response = chain.proceed(request);
            } catch (IOException e) {
                log.error("[okhttp time out] 请求 {}{} 超时", url.host(), url.encodedPath());
                throw e;
            }
            log.info(String.format("url: %s%s requestBodyString: %s response: %s", url.host(), url.encodedPath(), requestBodyString, JSON.toJSONString(response)));
            return response;
        }
    }

    /**
     * 重试
     */
    public static class RetryInterceptor implements Interceptor {
        private final int maxRetryCount;

        public RetryInterceptor(int maxRetryCount) {
            this.maxRetryCount = maxRetryCount;
        }

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            int retryCount = 0;
            while (retryCount < maxRetryCount) {
                try {
                    return chain.proceed(request);
                } catch (IOException e) {
                    if (++retryCount == maxRetryCount) {
                        throw e;
                    }
                }
            }

            throw new IOException("Max retry count reached");
        }
    }


}

UriUtil

import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Objects;

/**
 * @description:
 */
public class UriUtil {
    public static String generateUrlWithParams(String url, Map<String, Object> params) {
        StringBuilder resUrl = new StringBuilder(url);
        int i = 0;
        for (String key : params.keySet()) {
            if (Objects.isNull(params.get(key)) || StringUtils.isEmpty(params.get(key).toString())) {
                continue;
            }
            if (url.indexOf('?') != -1) {
                resUrl.append("&");
            } else {
                if (i == 0) {
                    resUrl.append("?");
                } else {
                    resUrl.append("&");
                }
            }
            Object param = params.get(key);
            try {
                param = URLEncoder.encode(param.toString(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // ignore
            }
            resUrl.append(key).append("=").append(param);
            i++;
        }
        return resUrl.toString();
    }
}