重试拦截器:
/**
* @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);
}