OkHttpUtils.java 11.6 KB
package com.huaheng.common.utils.http;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.huaheng.framework.aspectj.ApiLogAspect;
import com.huaheng.framework.web.service.ConfigService;
import com.huaheng.pc.monitor.apilog.domain.ApiLog;

import okhttp3.*;

/**
 * OkHttp发送请求
 * @author huaheng
 * @Date   2022-5-30
 */
public class OkHttpUtils {

    @Resource
    private ConfigService configService;

    private static final Logger log = LoggerFactory.getLogger(OkHttpUtils.class);

    /**
     * 最多重试次数
     */
    public final static int MAX_RENTRY_COUNT = 0;

    /**
     * 最大连接时间(秒)
     */
    public final static int CONNECTION_TIMEOUT = 1;

    /**
     * 最大读取时间(秒)
     */
    public final static int READ_TIMEOUT = 10;

    /**
     * 最大写入时间(秒)
     */
    public final static int WRITE_TIMEOUT = 10;

    /**
     * JSON格式
     */
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");

    /**
     * OkHTTP线程池最大空闲线程数
     */
    public final static int MAX_IDLE_CONNECTIONS = 40;

    /**
     * OkHTTP线程池空闲线程存活时间(秒)
     */
    public final static long KEEP_ALIVE_DURATION = 60;

    private static final String CONTENT_TYPE = "Content-Type";

    /**
     * client
     * 配置重试
     */
    /** 访问接口参数配置 */
    private final static OkHttpClient HTTP_CLIENT =
        new OkHttpClient.Builder().connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS).readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS).addInterceptor(new OkHttpUtils.OkhttpInterceptor(MAX_RENTRY_COUNT)) // 过滤器,设置最大重试次数
            .retryOnConnectionFailure(false).connectionPool(new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.SECONDS)).build();
//    private final static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder().readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
//        .writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS).connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
//        .connectionPool(new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.MINUTES)).build();
    private static final Gson GSON = new Gson();

    /**
     * 向指定 URL 发送GET方法的请求
     * @param  url 发送请求的 URL
     *             //* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return     所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        // headers 请求头
        Map<String, String> headers = new HashMap<>();
        // 请求URI
        String urlNameString = url + "?" + param;

        Request.Builder builder = new Request.Builder();
        buildHeader(builder, headers);

        Request request = builder.url(urlNameString).get().build();
        Response response = null;
        try {
            response = HTTP_CLIENT.newCall(request).execute();
            if (response.isSuccessful() && Objects.nonNull(response.body())) {
                String result = response.body().string();
                log.info("执行get请求, url: {} 成功,返回数据: {}", url, result);
                return result;
            }
        } catch (IOException e) {
            log.error("执行get请求,url: {} 失败!", url, e);
        }
        return "";
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * @param  url 发送请求的 URL
     *             // * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return     所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        FormBody.Builder builder = new FormBody.Builder();
        String urlNameString = url + "?" + param;
        FormBody body = builder.build();
        Request request = new Request.Builder().url(urlNameString).post(body).build();
        Response response = null;
        try {
            response = HTTP_CLIENT.newCall(request).execute();
            // 调用成功
            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String bodypost(String strURL, String json) {
        return bodypost(strURL, json, "", null);
    }

    // 此方法是将参数以body形式发送post请求
    public static String bodypost(String strURL, String json, String sessionId, String apiName) {
        ApiLog apiLog = null;
        // using above json body as a input to post API call
        RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
        // headers 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json");// 设置接收数据的格式
        headers.put("Content-Type", "application/json");// 设置发送数据的格式
        headers.put("kdservice-sessionid", sessionId);// 设置发送数据的格式
        Request.Builder builder = new Request.Builder();
        buildHeader(builder, headers);
        Request request = builder.url(strURL).post(body).build();
        Response response = null;
        String result = null;
        try {
            apiLog = ApiLogAspect.initApiLog(request, json);
            response = HTTP_CLIENT.newCall(request).execute();
            if (response.isSuccessful() && Objects.nonNull(response.body())) {
                result = response.body().string();
                log.info("执行post请求,url: {}, header: {} ,参数: {} 成功,返回结果: {}", strURL, headers, json, result);
            }
        } catch (IOException e) {
            ApiLogAspect.setApiLogException(apiLog, e);
            log.error("执行post请求,url: {},参数: {} 失败!", strURL, json, e);
        } finally {
            ApiLogAspect.finishApiLog(apiLog, response, result);
        }
        return result;
    }

    // 此方法是将参数以body形式发送post请求
    public static String bodypost(String strURL, String json, Map<String, String> params) {
        ApiLog apiLog = null;
        // using above json body as a input to post API call
        RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
        // headers 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json");// 设置接收数据的格式
        headers.put("Content-Type", "application/json");// 设置发送数据的格式
        headers.putAll(params);
        Request.Builder builder = new Request.Builder();
        buildHeader(builder, headers);
        Request request = builder.url(strURL).post(body).build();
        Response response = null;
        String result = null;
        try {
            apiLog = ApiLogAspect.initApiLog(request, json);
            response = HTTP_CLIENT.newCall(request).execute();
            if (response.isSuccessful() && Objects.nonNull(response.body())) {
                result = response.body().string();
                log.info("执行post请求,url: {}, header: {} ,参数: {} 成功,返回结果: {}", strURL, headers, json, result);
            }
        } catch (IOException e) {
            ApiLogAspect.setApiLogException(apiLog, e);
            log.error("执行post请求,url: {},参数: {} 失败!", strURL, json, e);
        } finally {
            ApiLogAspect.finishApiLog(apiLog, response, result);
        }
        return result;
    }

    // 此方法是将参数以body形式发送post请求
    public static Map<String,Object> getHeaderBodyPost(String strURL, String json, Map<String, String> params) {
        Map<String,Object> map = new HashMap<>();

        ApiLog apiLog = null;
        // using above json body as a input to post API call
        RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
        // headers 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json");// 设置接收数据的格式
        headers.put("Content-Type", "application/json");// 设置发送数据的格式
        headers.putAll(params);
        Request.Builder builder = new Request.Builder();
        buildHeader(builder, headers);
        Request request = builder.url(strURL).post(body).build();
        Response response = null;
        String result = null;
        try {
            apiLog = ApiLogAspect.initApiLog(request, json);
            response = HTTP_CLIENT.newCall(request).execute();
            if (response.isSuccessful() && Objects.nonNull(response.body())) {
                result = response.body().string();
                String labellocation = response.header("labellocation", null);
                map.put("labellocation",labellocation);
                map.put("printData",result);
                log.info("执行post请求,url: {}, header: {} ,参数: {} 成功,返回结果: {}", strURL, headers, json, result);
            }
        } catch (IOException e) {
            ApiLogAspect.setApiLogException(apiLog, e);
            log.error("执行post请求,url: {},参数: {} 失败!", strURL, json, e);
        } finally {
            ApiLogAspect.finishApiLog(apiLog, response, result);
        }
        return map;
    }

    /**
     * 设置请求头
     * @param builder .
     * @param headers 请求头
     */
    private static void buildHeader(Request.Builder builder, Map<String, String> headers) {
        if (Objects.nonNull(headers) && headers.size() > 0) {
            headers.forEach((k, v) -> {
                if (Objects.nonNull(k) && Objects.nonNull(v)) {
                    builder.addHeader(k, v);
                }
            });
        }
    }

    /**
     * 支持嵌套泛型的post请求。
     * 
     * <pre>
     * Type type = new TypeToken<Results<User>>() {}.getType();
     * 
     * <pre/>
     * @param  url  链接
     * @param  json 请求json
     * @param  type 嵌套泛型
     * @return      响应对象, 可进行强转。
     */
    public static <T> T post(String url, String json, Type type) {
        String result = bodypost(url, json);
        if (Objects.nonNull(result) && Objects.nonNull(type)) {
            return GSON.fromJson(result, type);
        }
        return null;
    }

    public static class OkhttpInterceptor implements Interceptor {

        // 最大重试次数
        private int maxRentry;

        public OkhttpInterceptor(int maxRentry) {
            this.maxRentry = maxRentry;
        }

        /** 递归 2次下发请求,如果仍然失败 则返回 null 但是 intercept must not return null. 返回 null 会报 IllegalStateException 异常 */
        public Response intercept(@NotNull Chain chain) throws IOException {
            return retry(chain, 0);
        }

        private Response retry(Chain chain, int retryCent) throws IOException {
            Request request = chain.request();
            Response response = null;
            try {
                response = chain.proceed(request);
            } catch (Exception e) {
                if (maxRentry > retryCent) {
                    return retry(chain, retryCent + 1);
                }
                if (Objects.isNull(response)) {
                    throw e;
                }
            }
            return response;
        }
    }
}