java使用okhttp利用拦截器实现自动重试

4,510 阅读2分钟

重试拦截器:

/**
 * @author shenweiquan
 * 重试拦截器
 */
@Slf4j
public class RetryInterceptor implements Interceptor {


    @Override
    public Response intercept(Chain chain) throws IOException {
        return retry(chain);
    }

    public Response retry(Chain chain) throws IOException {
        Request request = chain.request();
        ParentRetryRequestParam retryTag = request.tag(ParentRetryRequestParam.class);
        Response response = null;
        try {
            response = chain.proceed(request);
            if (!response.isSuccessful()
                    && Objects.nonNull(retryTag)
                    && retryTag.getCurrentCount() < retryTag.getRetryCount()) {
                retryTag.setCurrentCount(retryTag.getCurrentCount() + 1);
                response = retry(chain);
            }
        } catch (Exception e) {
            assert retryTag != null;
            log.info("RetryInterceptor: request {} is not successful-> request count {} because {}",
                    request.url(), retryTag.getCurrentCount(), e.getMessage());
            if (retryTag.getCurrentCount() < retryTag.getRetryCount()) {
                retryTag.setCurrentCount(retryTag.getCurrentCount() + 1);
                response = retry(chain);
            }
        }
        //同步请求直接抛出异常,外层调用函数处理,异步请求则进入回调接口处理。
        if (Objects.isNull(response)) {
            throw new IOException("重复请求" + retryTag.getCurrentCount() + "次后,请求失败");
        }
        return response;
    }
}

请求客户端

@Configuration
public class RequestClientConfig {

    /**
     *
     *
     * @return
     */
    @Bean
    public okhttp3.OkHttpClient OkHttpClient() {
        okhttp3.OkHttpClient okHttpClient = new okhttp3.OkHttpClient.Builder()
                .eventListenerFactory(HttpEventListener.FACTORY)
                //默认读取超时时间
                .readTimeout(10000, TimeUnit.MILLISECONDS)
                //默认连接超时时间
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                //默认写入超时时间
                .writeTimeout(10000, TimeUnit.MILLISECONDS)
                //关闭默认重试拦截器
                .retryOnConnectionFailure(false)
                //添加自定义重试拦截器    
                .addInterceptor(new RetryInterceptor())
                .build();
        return okHttpClient;
   }
 }

封装请求参数:

package com.baturu.pq.business.okhttp.param;

import com.baturu.pq.business.im.yunxin.param.ParentRetryRequestParam;
import com.baturu.pq.business.okhttp.config.TimeoutConfig;
import lombok.Builder;
import lombok.Data;

import java.util.Map;

/**
 * http 请求参数
 *
 * @author shenweiquan
 */
@Data
@Builder
public class HttpRequestParam {
    /**
     * 请求地址
     */
    private String url;
    /**
     * 超时设置
     */
    private TimeoutConfig timeoutConfig;
    /**
     * 请求头部
     */
    private Map<String, String> headerMap;
    /**
     * 请求参数
     */
    private Map<String, Object> paramMap;
    /**
     * 重试参数
     */
    private ParentRetryRequestParam retryRequestParam;
    /**
     * 是否已表单形式提交
     */
    private Boolean isForm;
    /**
     * 请求体 json提交
     */
    private Object body;
}

封装好的工具类:

package com.baturu.pq.business.okhttp.util;

import com.alibaba.fastjson.JSON;
import com.baturu.pq.business.im.yunxin.param.ParentRetryRequestParam;
import com.baturu.pq.business.okhttp.callback.OkHttpCallback;
import com.baturu.pq.business.okhttp.config.TimeoutConfig;
import com.baturu.pq.business.okhttp.param.HttpRequestParam;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.http.NameValuePair;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * okHttp 工具类
 *
 * @author shenweiquan
 */
@Slf4j
@Builder
public class OkHttpUtils {

    private OkHttpClient client;

    /**
     * @param client
     */
    public OkHttpUtils(OkHttpClient client) {
        this.client = client;
    }

    /**
     * 同步post请求
     */
    public Response httpPostSync(HttpRequestParam param) {
        Request.Builder request = this.httpPost(param);
        try (Response response = client.newCall(request.build()).execute()) {
            return response;
        } catch (IOException e) {
            log.error("发送请求异常, url:{};{}", param.getUrl(), e);
            return null;
        }
    }

    /**
     * 异步post请求
     */
    public void httpPostAsync(HttpRequestParam param, OkHttpCallback okHttpCallback) {
        Request.Builder request = this.httpPost(param);
        this.async(request, okHttpCallback);
    }

    /**
     * 同步get请求
     */
    public Response httpGetSync(HttpRequestParam param) {
        Request.Builder request = this.httpGet(param);
        try (Response response = client.newCall(request.build()).execute()) {
            return response;
        } catch (IOException e) {
            log.error("发送请求异常, url:{};{}", param.getUrl(), e);
            return null;
        }
    }

    public void httpGetAsync(HttpRequestParam param, OkHttpCallback callback) {
        Request.Builder request = this.httpGet(param);
        this.async(request, callback);
    }

    /**
     * 构造post请求
     *
     * @param param
     * @return
     */
    private Request.Builder httpPost(HttpRequestParam param) {
        Request.Builder request = new Request.Builder();
        request.url(param.getUrl());
        if (Objects.nonNull(param.getHeaderMap())) {
            this.setHeader(request, param.getHeaderMap());
        }
        //自定义超时时间
        if (Objects.nonNull(param.getTimeoutConfig())) {
            request.tag(TimeoutConfig.class, param.getTimeoutConfig());
        }
        //自定义重试次数
        if (Objects.nonNull(param.getRetryRequestParam())) {
            request.tag(ParentRetryRequestParam.class, param.getRetryRequestParam());
        }
        if (Objects.nonNull(param.getIsForm()) && BooleanUtils.isTrue(param.getIsForm())) {
            List<NameValuePair> bodyForm = JSON.parseArray(JSON.toJSONString(param.getBody()), NameValuePair.class);
            this.bodyForm(request, bodyForm);
        } else {
            this.body(request, param.getBody());
        }
        return request;
    }

    /**
     * 构造get请求
     */
    public Request.Builder httpGet(HttpRequestParam param) {
        Request.Builder request = new Request.Builder().get();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(param.getUrl()).newBuilder();
        if (Objects.nonNull(param.getParamMap())) {
            //拼接get请求参数
            for (Map.Entry<String, Object> entry : param.getParamMap().entrySet()) {
                urlBuilder.addQueryParameter(entry.getKey(), entry.getValue().toString());
            }
        }
        request.url(urlBuilder.build());
        this.setHeader(request, param.getHeaderMap());
        //自定义超时时间
        if (Objects.nonNull(param.getTimeoutConfig())) {
            request.tag(TimeoutConfig.class, param.getTimeoutConfig());
        }
        //自定义重试次数
        if (Objects.nonNull(param.getRetryRequestParam())) {
            request.tag(ParentRetryRequestParam.class, param.getRetryRequestParam());
        }
        return request;
    }

    /**
     * 表单方式提交
     *
     * @param bodyForm
     * @return
     */
    private void bodyForm(Request.Builder request, List<NameValuePair> bodyForm) {
        FormBody.Builder formBody = new FormBody.Builder();
        bodyForm.stream()
                .map(v -> {
                    return formBody.add(v.getName(), v.getValue());
                });
        RequestBody requestBody = formBody.build();
        request.post(requestBody);
    }

    /**
     * json方式提交
     *
     * @return
     */
    private void body(Request.Builder request, Object body) {
        String jsonStr = "";
        if (Objects.nonNull(body)) {
            jsonStr = JSON.toJSONString(body);
        }
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonStr);
        request.post(requestBody);
    }

    /**
     * 设置请求头
     *
     * @param request
     */
    private void setHeader(Request.Builder request, Map<String, String> headerMap) {
        if (Objects.nonNull(headerMap)) {
            try {
                for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                    request.addHeader(entry.getKey(), entry.getValue());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 异步请求
     * 接口回调
     *
     * @param okHttpCallback
     */
    public void async(Request.Builder request, OkHttpCallback okHttpCallback) {
        client.newCall(request.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                okHttpCallback.failed(call, e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                okHttpCallback.success(call, response);
            }
        });
    }


}

测试:

/**
 * 测试同步get请求 超时+重试
 */
@Test
public void test4() {
    HttpRequestParam requestParam = HttpRequestParam.builder()
            .url("https://github.com")
            .timeoutConfig(TimeoutConfig.builder().socketTimeout(1).build())
            .retryRequestParam(new ParentRetryRequestParam(10, 1))
            .build();
    Dispatcher dispatcher = client.dispatcher();
    /**
     * 最大请求数量
     */
    dispatcher.setMaxRequests(64);
    /**
     * 同一域名同时存在的最大请求数量
     */
    dispatcher.setMaxRequestsPerHost(8);
    OkHttpUtils okHttpUtils = OkHttpUtils.builder()
            .client(client.newBuilder()
                    .addInterceptor(new TimeoutInterceptor())
                    .addInterceptor(new RetryInterceptor())
                    .build())
            .build();
    okHttpUtils.httpGetSync(requestParam);
}