OkHttp使用
2023-07-06

OkHttp使用

介绍

OkHttp是一个网络应用编程工具,适用于 Android 5.0+(API 级别 21+)和 Java 8+。

官方链接:https://square.github.io/okhttp/

java中使用

maven中引入:

<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
 <groupId>com.squareup.okhttp3</groupId>
 <artifactId>okhttp</artifactId>
 <version>3.10.0</version>
</dependency>
<!--常用工具集-->
<dependency>
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>5.8.16</version>
</dependency>

HttpClientUtil 代码,其中 HttpRequestException RetryFunction 为自定义类

HttpRequestException 为http请求的全局异常,RetryFunction为重试函数, 包含参数重试次数与重试间隔(秒)

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.json.JSONUtil;
import common.exception.HttpRequestException;
import okhttp3.*;

import java.io.IOException;
import java.net.Proxy;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class HttpClientUtil {

    private volatile static HttpClientUtil httpClientUtil;

    private OkHttpClient httpClient = null;

    static final MediaType JSON_TYPE = MediaType.parse("application/json");

    private HttpClientUtil() {

    }

    /**
     * 生成一个 httpClientUtil实例,初始化 okhttpClient参数
     *
     * @return
     */
    public static synchronized HttpClientUtil getInstance() {
        if (httpClientUtil == null) {
            httpClientUtil = new HttpClientUtil();
        }
        httpClientUtil.initOkHttpClient();
        return httpClientUtil;
    }

    public HttpClientUtil initOkHttpClient() {
        OkHttpClient.Builder builder;
        if (this.httpClient == null) {
            builder = new OkHttpClient.Builder();
        } else {
            builder = httpClient.newBuilder();
        }
        this.httpClient = builder
                .connectionPool(new ConnectionPool(200, 10, TimeUnit.SECONDS))
                .connectTimeout(2, TimeUnit.SECONDS)
                .readTimeout(2, TimeUnit.SECONDS)
                .build();
        return this;
    }

    public HttpClientUtil initOkHttpClient(Proxy proxy, Authenticator authenticator) {
        this.httpClient = httpClient.newBuilder()
                .connectionPool(new ConnectionPool(200, 10, TimeUnit.SECONDS))
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .proxy(proxy)
                .proxyAuthenticator(authenticator)
                .build();
        return this;
    }

    public String doGet(String url, Map<String, Object> params) {

        HttpUrl.Builder urlBuilder = HttpUrl.parse(UrlBuilder.ofHttp(url).build()).newBuilder();
        if (MapUtil.isNotEmpty(params)) {
            params.forEach((k, v) -> {
                urlBuilder.addQueryParameter(k, v.toString());
            });
        }
        Request.Builder reqBuild = new Request.Builder();
        reqBuild.url(urlBuilder.build());

        Response response = RetryFunction.retry(5, 1, () -> {
            try {
                return httpClient.newCall(reqBuild.build()).execute();
            } catch (IOException e) {
                throw new RuntimeException("http get请求执行异常,url=" + url, e);
            }
        });
        return checkResponse(response);
    }

    public String doPost(String url, Map<String, Object> params) {
        RequestBody body = RequestBody.create(JSON_TYPE, JSONUtil.toJsonStr(params));
        Request.Builder reqBuild = new Request.Builder().url(url).post(body);

        Response response = RetryFunction.retry(5, 1, () -> {
            try {
                return httpClient.newCall(reqBuild.build()).execute();
            } catch (IOException e) {
                throw new RuntimeException("http post请求执行异常,url=" + url, e);
            }
        });
        return checkResponse(response);
    }

    private String checkResponse(Response response) {
        try {
            return response.body().string();
        } catch (IOException e) {
            throw new HttpRequestException("http结果解析异常,解析内容为:" + response, e);
        }
    }
}

import common.exception.RetryException;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Supplier;
@Slf4j
public class RetryFunction<R> {


    public static <R> R retry(long retryCount, long interval, Supplier<R> supplier){
        Long retryCountBack = retryCount;
        Boolean success = Boolean.FALSE;
        R result = null;
        //还有重试次数并且未成功的时候
        while (retryCount > 0 && !success) {
            try {
                result = supplier.get();
                if(result != null){
                    success = Boolean.TRUE;
                }
            }catch (Exception e){
                log.error("接口请求失败,本次错误的信息为:{}, 剩余尝试次数为:{}", e.getMessage(), retryCount);
            }
            retryCount--;

            try {
                Thread.sleep(interval);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        if(result == null){
            throw new RetryException("接口尝试"+ retryCountBack +"次后依然失败。");
        }
        return result;
    }
}

public class HttpRequestException extends RuntimeException{

    public HttpRequestException() {
    }

    public HttpRequestException(String message) {
        super(message);
    }

    public HttpRequestException(String message, Throwable cause) {
        super(message, cause);
    }

    public HttpRequestException(Throwable cause) {
        super(cause);
    }

    public HttpRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

创建实例方法,可按情况是否使用代理发起请求

import common.util.HttpClientUtil;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;

@Configuration
public class HttpClientConfig {

    @Value("${proxy.hostname}")
    private String hostname;

    @Value("${proxy.port}")
    private Integer port;

    @Value("${proxy.username}")
    private String username;
    @Value("${proxy.password}")
    private String password;

    @Bean
    HttpClientUtil client(){
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(hostname, port));

        Authenticator authenticator = null;
        if(username != null){
            authenticator = (route, response) -> response.request().newBuilder()
                    .header("Proxy-Authorization", Credentials.basic(username, password))
                    .build();
        }
        return HttpClientUtil.getInstance().initOkHttpClient(proxy, authenticator);
    }

}