(Java)高性能Http框架:OKHttp3的工具类OkHttp3Utils实现(可使用Http代理)

前言

网上的类似工具类已经很多了,自己优化了一些,希望大家多多给到意见

实现

OkHttp3Utils(主类)

说明一下几个特殊类,可以在实际使用过程中按需替换

  • SkynetUtils:封装了公司内部日志系统日志记录功能的实现类(记录日志)
  • EnumSkynetCategoryPublicUtils(记录日志用)
  • EnumSkynetLogModule(记录日志用)
package demo.common.utls;

import com.google.gson.Gson;
import demo.common.enumlibrary.skynet.category.EnumSkynetCategoryPublicUtils;
import demo.common.enumlibrary.skynet.EnumSkynetLogModule;
import demo.model.proxy.ProxyDO;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * OkHttp3Utils
 * 通过OKHttp3构建的Http请求方法
 *
 * @author John Chen
 * @since 2018/10/11
 */
public class OkHttp3Utils {
    private final static String MODULE = EnumSkynetLogModule.PUBLIC_UTILS.getName();
    private final static String CATEGORY = EnumSkynetCategoryPublicUtils.OKHTTP3.getName();
    private OkHttpClient client = new OkHttpClient();
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static final MediaType URL_ENCODED = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
    public static final MediaType FORM_DATA = MediaType.parse("multipart/form-data; charset=utf-8");
    public static final MediaType XML = MediaType.parse("text/xml; charset=utf-8");

    private Gson gson = new Gson();
    private int connectTimeout = 3;

    private int requestTimeout = 6;

    private int readTimeout = 6;

    //region 构造方法

    /**
     * 构建方法,默认超时时间
     */
    public OkHttp3Utils() {
        this(0, 0, 0);
    }

    /**
     * 构建方法,自定义读取超时(推荐)
     *
     * @param readTimeout 读取超时时间
     */
    public OkHttp3Utils(int readTimeout) {
        this(readTimeout, 0, 0);
    }

    /**
     * 默认方法,自定义写入超时\读取超时(不推荐)
     *
     * @param readTimeout    读取超时时间
     * @param requestTimeout 写入超时时间
     */
    public OkHttp3Utils(int readTimeout, int requestTimeout) {
        this(readTimeout, requestTimeout, 0);

    }

    /**
     * 默认方法,自定义写入超时\读取超时\连接超时(不推荐)
     *
     * @param readTimeout    读取超时时间
     * @param requestTimeout 写入超时时间
     * @param connectTimeout 连接超时时间
     */
    public OkHttp3Utils(int readTimeout, int requestTimeout, int connectTimeout) {
        this(readTimeout, requestTimeout, connectTimeout, null);
    }

    /**
     * 默认方法,自定义写入超时\读取超时\连接超时(不推荐)
     *
     * @param readTimeout    读取超时时间
     * @param requestTimeout 写入超时时间
     * @param connectTimeout 连接超时时间
     * @param proxyDO        代理实体
     */
    public OkHttp3Utils(int readTimeout, int requestTimeout, int connectTimeout, ProxyDO proxyDO) {
        this.requestTimeout = requestTimeout > 0 ? requestTimeout : this.requestTimeout;
        this.readTimeout = readTimeout > 0 ? readTimeout : this.readTimeout;
        this.connectTimeout = connectTimeout > 0 ? connectTimeout : this.connectTimeout;
        OkHttpClient.Builder builder = client.newBuilder().connectTimeout(this.connectTimeout, TimeUnit.SECONDS)
                .writeTimeout(this.requestTimeout, TimeUnit.SECONDS).readTimeout(this.readTimeout, TimeUnit.SECONDS);
        if (proxyDO != null) {
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyDO.getServiceAddress(), Integer.parseInt(proxyDO.getPort())));
            builder.proxy(proxy);
            if (!StringUtils.isEmpty(proxyDO.getUserName())) {
                String userName = proxyDO.getUserName();
                String password = proxyDO.getPassword();
                Authenticator proxyAuthenticator = (route, response) -> {
                    String credential = Credentials.basic(userName, password == null ? "" : password);
                    return response.request().newBuilder()
                            .header("Proxy-Authorization", credential)
                            .build();
                };
                builder.proxyAuthenticator(proxyAuthenticator);
            }
        }
        client = builder.build();
    }
    //endregion


    //region Post方法集合

    /**
     * post请求方法.默认使用Json方式通信
     *
     * @param url url
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url) throws IOException {
        return post(url, "", null, null, null);
    }

    /**
     * post请求方法.默认使用Json方式通信
     *
     * @param url          url
     * @param requestParam 请求参数,会放在url中
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, Map<String, Object> requestParam) throws IOException {
        return post(url, "", null, requestParam, null);
    }

    /**
     * post请求方法.默认使用Json方式通信
     *
     * @param url      url
     * @param jsonBody 请求体
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, @NotNull String jsonBody) throws IOException {
        return post(url, jsonBody, null, null, null);
    }

    /**
     * post请求方法.默认使用Json方式通信
     *
     * @param url          url
     * @param jsonBody     请求体
     * @param requestParam 请求参数,会放入url中
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, @NotNull String jsonBody, Map<String, Object> requestParam) throws IOException {
        return post(url, jsonBody, null, requestParam, null);
    }

    /**
     * post请求方法
     *
     * @param url       url
     * @param body      请求体
     * @param mediaType post请求类型。传Null则默认application/json; charset=utf-8
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, @NotNull String body, MediaType mediaType) throws IOException {
        return post(url, body, mediaType, null, null);

    }

    /**
     * post请求方法
     *
     * @param url          url
     * @param body         请求体
     * @param mediaType    post请求类型。传Null则默认application/json; charset=utf-8
     * @param requestParam 请求地址参数,可以为null
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, @NotNull String body, MediaType mediaType, Map<String, Object> requestParam) throws IOException {
        return post(url, body, mediaType, requestParam, null);

    }

    /**
     * post请求的底层方法
     *
     * @param url           请求地址
     * @param body          请求体
     * @param mediaType     post请求类型。传Null则默认application/json; charset=utf-8
     * @param requestParam  请求地址参数,可以为null
     * @param requestHeader 请求头,可以为null
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String post(@NotNull String url, @NotNull String body, MediaType mediaType, Map<String, Object> requestParam, Map<String, String> requestHeader) throws IOException {
        HttpUrl httpUrl = new HttpUrl(url, requestParam);
        Response response = execute(httpUrl, requestHeader, body, mediaType);
        return responseToString(response, url, requestParam);
    }
    //endregion

    /**
     * 用于处理response
     *
     * @param response     返回实体
     * @param url          地址
     * @param requestParam 地址参数
     * @return 返回Body中的String
     */
    private String responseToString(Response response, String url, Map<String, Object> requestParam) throws IOException {
        if (!response.isSuccessful()) {
            String errorString = "请求失败,响应码:" + response.code()
                    + ";uri:" + url
                    + ";requestParam:" + (requestParam == null ? "null" : gson.toJson(requestParam))
                    + ";错误信息:" + (response.body() != null ? response.body().string() : "null");
            SkynetUtils.printWarn(errorString, MODULE, CATEGORY, "post", "", "");
            throw new IllegalStateException(errorString);
        }

        return response.body() == null ? "" : response.body().string();
    }


    //region get请求方法集

    /**
     * get请求的底层方法
     *
     * @param url 请求地址
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String get(@NotNull String url) throws IOException {
        return get(url, null, null);
    }

    /**
     * get请求的底层方法
     *
     * @param url          请求地址
     * @param requestParam 请求地址参数,可以为null
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String get(@NotNull String url, Map<String, Object> requestParam) throws IOException {
        return get(url, requestParam, null);
    }

    /**
     * get请求的底层方法
     *
     * @param url           请求地址
     * @param requestParam  请求地址参数,可以为null
     * @param requestHeader 请求头,可以为null
     * @return 返回请求体
     * @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
     */
    public String get(@NotNull String url, Map<String, Object> requestParam, Map<String, String> requestHeader) throws IOException {
        HttpUrl httpUrl = new HttpUrl(url, requestParam);
        Response response = execute(httpUrl, requestHeader, null, null);
        return responseToString(response, url, requestParam);
    }
    //endregion


    //region 底层请求方法

    /**
     * 请求底层方法
     *
     * @param httpUrl       URL实体
     * @param requestHeader Header信息。无Header信息时传null
     * @param body          请求体。当body=null时使用get方法,否则使用post方法
     * @param mediaType     Post方法的请求方法
     * @return 返回实体
     * @throws IOException 请求时可能抛出的异常
     */
    public Response execute(@NotNull HttpUrl httpUrl, Map<String, String> requestHeader, String body, MediaType mediaType) throws IOException {
        URL url;
        url = httpUrl.build();
        //region 构建RequestBody
        Request request;
        if (body == null) {
            request = new Request.Builder().url(url).build();
        } else {
            MediaType media = mediaType != null ? mediaType : JSON;
            RequestBody requestBody = RequestBody.create(media, body);
            request = new Request.Builder().url(url).post(requestBody).build();
        }
        //endregion

        //region 添加Header
        if (requestHeader != null && requestHeader.size() > 0) {
            for (Map.Entry<String, String> s : requestHeader.entrySet()) {
                request = request.newBuilder().addHeader(s.getKey(), s.getValue()).build();
            }
        }
        //endregion
        return execute(request);


    }

    /**
     * request
     * 底层请求方法
     * 过滤了空的返回实体
     *
     * @param request 请求体
     * @return 返回Response
     * @throws IOException HTTP请求可能抛出异常
     */
    public Response execute(Request request) throws IOException {
        Response response = client.newCall(request).execute();
        Objects.requireNonNull(response, "response为空, request is :" + request);

        return response;
    }

    /**
     * 异步Request方法
     *
     * @param request          请求体
     * @param responseCallback callBack方法
     */
    public void enqueue(Request request, Callback responseCallback) {
        client.newCall(request).enqueue(responseCallback);
    }
    //endregion
}

ProxyDO(代理实体)

如果要使用代理,则先构建这个代理实体

package demo.model.proxy;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.NotBlank;

/**
 * ProxyDO
 *
 * @author 陈伟伟 John Chen [email protected]
 * @since 2019/11/15
 */
@Data
@AllArgsConstructor
public class ProxyDO {
    /**
     * 服务地址(用于代理服务的地址)(必填)
     */
    @NotBlank
    private String serviceAddress;
    /**
     * 端口(必填)
     */
    @NotBlank
    private String port;
    /**
     * 内网IP(选填,通常用于IP切换等Job中)
     */
    private String innerIp;
    /**
     * 用户名(选填,如有)
     */
    private String userName;
    /**
     * 密码(选填,如有)
     */
    private String password;

    /**
     * 获取连接字符串
     * 格式:[serviceAddress]:[port]{:[userName]:[password]}
     *
     * @return 返回用于代理连接的字符串
     */
    public String getProxyContentStr() {
        StringBuilder stringBuilder = new StringBuilder(serviceAddress + ":" + port);
        if (!StringUtils.isEmpty(userName)) {
            stringBuilder.append(":").append(userName);
            if (!StringUtils.isEmpty(password)) {
                stringBuilder.append(":").append(password);
            }
        }
        return stringBuilder.toString();
    }

}
发布了7 篇原创文章 · 获赞 12 · 访问量 2286

猜你喜欢

转载自blog.csdn.net/weixin_42182797/article/details/105586759