![JAR search and dependency download from the Maven repository](/logo.png)
com.mzlion.easyokhttp.request.AbsHttpRequest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of easy-okhttp Show documentation
Show all versions of easy-okhttp Show documentation
easy-okhttp是对okhttp3上层封装的网络框架,支持文件上传和下载表单提交(文件和一个参数对应多值),
链式调用,并且默认整合Gson,对返回结果多种转换,同时还支持HTTPS单向认证和双向认证等特性。
The newest version!
/*
* Copyright (C) 2016-2017 mzlion([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mzlion.easyokhttp.request;
import com.mzlion.core.io.IOUtils;
import com.mzlion.core.json.TypeRef;
import com.mzlion.core.lang.Assert;
import com.mzlion.core.lang.CollectionUtils;
import com.mzlion.core.lang.StringUtils;
import com.mzlion.easyokhttp.HttpClient;
import com.mzlion.easyokhttp.exception.HttpClientConfigException;
import com.mzlion.easyokhttp.exception.HttpClientException;
import com.mzlion.easyokhttp.exception.HttpStatusCodeException;
import com.mzlion.easyokhttp.http.Header;
import com.mzlion.easyokhttp.http.ProcessRequestBody;
import com.mzlion.easyokhttp.response.HttpResponse;
import com.mzlion.easyokhttp.response.callback.Callback;
import com.mzlion.easyokhttp.utils.SSLContexts;
import com.mzlion.easyokhttp.utils.Utils;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
*
* 2016-04-16 {@linkplain HttpRequest}的抽象实现,实现了大部分方法.
*
*
* @author mzlion on 2016-04-16
*/
@SuppressWarnings("unchecked")
public abstract class AbsHttpRequest> implements HttpRequest {
protected Logger logger = LoggerFactory.getLogger(AbsHttpRequest.class);
protected String url;
/**
* 连接超时时间
*/
private TimeoutHolder connectTimeout;
/**
* 流读取超时时间
*/
private TimeoutHolder readTimeout;
/**
* 流写入超时时间
*/
private TimeoutHolder writeTimeout;
/**
* SSL证书文件列表
*/
private CertificateHolder certificateHolder = null;
/**
* 存储请求头信息
*/
private Map headers;
private Map> queryParams;
/**
* default constructor
*
* @param url 请求地址
*/
AbsHttpRequest(String url) {
this.url = url;
this.headers = new LinkedHashMap<>();
this.queryParams = new LinkedHashMap<>();
//设置默认的User-Agent和Accept-Language
this.header(Header.ACCEPT_LANGUAGE, Utils.getAcceptLanguage());
this.header(Header.USER_AGENT, Utils.getUserAgent());
}
/**
* 设置请求地址
*
* @param url 请求地址
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req url(String url) {
this.url = url;
return (Req) this;
}
//region===============为URL后面追加参数===============
/**
* 为url地址设置请求参数,即url?username=admin pwd=123
*
* @param name 参数名
* @param value 参数值
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req queryString(String name, Number value) {
return this.queryString(name, value == null ? null : value.toString());
}
/**
* 为url地址设置请求参数,即url?username=admin pwd=123
*
* @param name 参数名
* @param value 参数值
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req queryString(String name, String value) {
return this.queryString(name, value, false);
}
/**
* 为url地址设置请求参数,即url?username=admin pwd=123
*
* @param name 参数名
* @param value 参数值
* @param replace 值为[@code true}则替换
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req queryString(String name, String value, boolean replace) {
//Assert.hasLength(name, "Name must not be null.");
if (StringUtils.isEmpty(name)) return (Req) this;
if (!replace && value == null) {
logger.warn(" ===> The value is null,ignore:name={},value=null", name);
return (Req) this;
}
List valueList = this.queryParams.get(name);
if (valueList == null) {
valueList = new LinkedList<>();
this.queryParams.put(name, valueList);
}
if (replace) valueList.clear();
valueList.add(value);
return (Req) this;
}
/**
* 为url地址设置请求参数,即url?username=admin pwd=123
*
* @param parameters 参数对
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req queryString(Map parameters) {
//Assert.notEmpty(parameters, "Parameters may not be null or empty.");
if (CollectionUtils.isEmpty(parameters)) return (Req) this;
for (Map.Entry entry : parameters.entrySet()) {
this.queryString(entry.getKey(), entry.getValue());
}
return (Req) this;
}
//endregion===============为URL后面追加参数===============
//region===============设置HTTP Header===============
/**
* 添加请求头信息
*
* @param name 请求头键名
* @param value 请求头值
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req header(String name, String value) {
//Assert.hasLength(name, "Name may not be null or empty.");
//Assert.notNull(value, "Value may not be null.");
if (StringUtils.hasLength(name) && null != value)
this.headers.put(name, value);
return (Req) this;
}
/**
* 从请求头中移除键值
*
* @param name 请求头键名
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req removeHeader(String name) {
//Assert.hasLength(name, "Name may noy be null or empty.");
if (StringUtils.hasLength(name))
this.headers.remove(name);
return (Req) this;
}
//endregion===============设置HTTP Header===============
//region===============覆盖配置HttpClient===============
/**
* 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain OkHttpClient}。
*
* @param connectTimeout 连接超时时间
* @param timeUnit 超时时间单位
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req connectTimeout(int connectTimeout, TimeUnit timeUnit) {
if (connectTimeout < 0) throw new HttpClientConfigException("Connect Timeout may be than 0.");
if (timeUnit == null) throw new HttpClientConfigException("TimeUnit may not be null.");
this.connectTimeout = new TimeoutHolder(connectTimeout, timeUnit);
return (Req) this;
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain OkHttpClient}。
*
* @param connectTimeout 连接超时时间
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req connectTimeout(int connectTimeout) {
return connectTimeout(connectTimeout, TimeUnit.SECONDS);
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独读取流超时。
*
* @param readTimeout 流读取超时时间
* @param timeUnit 超时时间单位
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req readTimeout(int readTimeout, TimeUnit timeUnit) {
if (readTimeout < 0) throw new HttpClientConfigException("Read Timeout may be than 0.");
if (timeUnit == null) throw new HttpClientConfigException("TimeUnit may not be null.");
this.readTimeout = new TimeoutHolder(readTimeout, timeUnit);
return (Req) this;
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独读取流超时。
*
* @param readTimeout 流读取超时时间
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req readTimeout(int readTimeout) {
return readTimeout(readTimeout, TimeUnit.SECONDS);
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独写入流超时。
*
* @param writeTimeout 流写入超时时间
* @param timeUnit 超时时间单位
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req writeTimeout(int writeTimeout, TimeUnit timeUnit) {
if (writeTimeout < 0) throw new HttpClientConfigException("Write Timeout may be than 0.");
if (timeUnit == null) throw new HttpClientConfigException("TimeUnit may not be null.");
this.writeTimeout = new TimeoutHolder(writeTimeout, timeUnit);
return (Req) this;
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独写入流超时。
*
* @param writeTimeout 流写入超时时间
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req writeTimeout(int writeTimeout) {
return writeTimeout(writeTimeout, TimeUnit.SECONDS);
}
/**
* 为构建本次{@linkplain HttpRequest}设置单独SSL证书
*
* @param certificates SSL证书文件
* @return 返回当前类{@link Req}的对象自己
*/
@Override
public Req customSSL(InputStream... certificates) {
return customSSL(null, null, certificates);
}
/**
* 为构建本次{@linkplain HttpRequest}设置SSL单向认证
*
* @param trustManager 证书管理器
* @return 返回当前类{@linkplain Req}的对象自己
*/
@Override
public Req customSSL(X509TrustManager trustManager) {
return customSSL(null, null, trustManager);
}
/**
* SSL双向认证
*
* @param pfxStream 客户端证书,支持P12的证书
* @param pfxPwd 客户端证书密码
* @param certificates 含有服务端公钥的证书
* @return {@link Req}
*/
@Override
public Req customSSL(InputStream pfxStream, char[] pfxPwd, InputStream... certificates) {
this.certificateHolder = new CertificateHolder(certificates, null, pfxStream, pfxPwd);
return (Req) this;
}
/**
* SSL双向认证
*
* @param pfxStream 客户端证书,支持P12的证书
* @param pfxPwd 客户端证书密码
* @param trustManager 证书管理器
* @return {@link Req}
*/
@Override
public Req customSSL(InputStream pfxStream, char[] pfxPwd, X509TrustManager trustManager) {
this.certificateHolder = new CertificateHolder(null, trustManager, pfxStream, pfxPwd);
return (Req) this;
}
//endregion===============覆盖配置HttpClient===============
//region===============增加了便捷转换方法===============
/**
* 将响应结果转为字符串
*
* @return 响应结果字符串
* @throws HttpClientException 如果服务器返回非200则抛出此异常
*/
public String asString() {
return execute().asString();
}
/**
* 将响应结果转为JavaBean对象
*
* @param targetClass 目标类型
* @param 泛型类型
* @return JavaBean对象
* @throws HttpClientException 如果服务器返回非200则抛出此异常
*/
public E asBean(Class targetClass) {
return this.execute().asBean(targetClass);
}
/**
* 将响应结果转为JavaBean对象
*
* 用法如下:Map<String,String> data = httpResponse.asBean(new TypeRef<Map<String,String>>);
*
*
* @param typeRef 带有泛型类的封装类
* @param 泛型类型
* @return JavaBean对象
* @throws HttpClientException 如果服务器返回非200则抛出此异常
*/
public E asBean(TypeRef typeRef) {
return this.execute().asBean(typeRef);
}
/**
* 将响应结果转为字节数组
*
* @return 字节数组
* @throws HttpClientException 如果服务器返回非200则抛出此异常
*/
public byte[] asByteData() {
return this.execute().asByteData();
}
/**
* 将响应结果输出到文件中
*
* @param saveFile 目标保存文件,非空
*/
public void asFile(File saveFile) {
this.execute().asFile(saveFile);
}
/**
* 将响应结果输出到输出流,并不会主动关闭输出流{@code out}
*
* @param out 输出流,非空
*/
public void asStream(OutputStream out) {
this.execute().asStream(out);
}
//endregion
/**
* 执行HTTP请求,获取响应结果
*
* @return 将响应结果转为具体的JavaBean
*/
@Override
public HttpResponse execute() {
RequestBody requestBody = this.generateRequestBody();
Request request = this.generateRequest(requestBody);
Call call = this.generateCall(request);
Response response = null;
try {
response = call.execute();
ResponseBody responseBody = response.body();
byte[] byteData = responseBody.bytes();
Response newResponse = response.newBuilder()
.body(ResponseBody.create(responseBody.contentType(), byteData))
.build();
HttpResponse httpResponse = new HttpResponse(newResponse);
httpResponse.setErrorMessage(response.message());
httpResponse.setHttpCode(response.code());
if (response.code() < 200 || response.code() >= 300) {
httpResponse.setSuccess(false);
return httpResponse;
} else {
httpResponse.setSuccess(true);
}
return httpResponse;
} catch (IOException e) {
throw new HttpClientException(e);
} finally {
IOUtils.closeQuietly(response);
}
}
/**
* 异步执行请求
*
* @param callback 回调接口
* @param 数据类型
*/
@Override
public void execute(Callback callback) {
Callback _cb = callback;
if (_cb == null) _cb = Callback.EMPTY_CALLBACK;
if (!callback.onBefore(this)) {
return;
}
final Callback finalCb = _cb;
ProcessRequestBody processRequestBody = new ProcessRequestBody(this.generateRequestBody(), new ProcessRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesWritten, long contentLength) {
finalCb.postProgress(bytesWritten, contentLength, 1.0f * bytesWritten / contentLength);
}
});
Call call = this.generateCall(this.generateRequest(processRequestBody));
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(Call call, IOException e) {
finalCb.onError(call, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
finalCb.onComplete(response);
if (response.code() >= 200 && response.code() < 300) {
try {
finalCb.onSuccess(finalCb.getDataHandler() == null ? null : finalCb.getDataHandler().handle(response));
} finally {
response.close();
}
} else {
finalCb.onError(call, new HttpStatusCodeException(url, response.code(), response.message()));
}
}
});
}
/**
* 获取{@linkplain RequestBody}对象
*
* @return {@linkplain RequestBody}
*/
protected abstract RequestBody generateRequestBody();
/**
* 根据不同的请求方式,将RequestBody转换成Request对象
*
* @param requestBody 请求体
* @return {@link Request}
* @see RequestBody
*/
protected abstract Request generateRequest(RequestBody requestBody);
/**
* 执行请求调用
*
* @param request Request对象
* @return {@linkplain Call}
*/
private Call generateCall(Request request) {
if (readTimeout == null && connectTimeout == null &&
writeTimeout == null && certificateHolder == null) {
return HttpClient.Instance.getOkHttpClient().newCall(request);
}
OkHttpClient.Builder builder = HttpClient.Instance.getOkHttpClientBuilder();
if (connectTimeout != null) builder.connectTimeout(connectTimeout.timeout, connectTimeout.timeUnit);
if (readTimeout != null) builder.readTimeout(readTimeout.timeout, readTimeout.timeUnit);
if (writeTimeout != null) builder.writeTimeout(writeTimeout.timeout, writeTimeout.timeUnit);
if (certificateHolder != null) {
SSLContexts.SSLConfig sslConfig = SSLContexts.tryParse(certificateHolder.certificates,
certificateHolder.trustManager, certificateHolder.pfxStream, certificateHolder.pfxPwd);
builder.sslSocketFactory(sslConfig.getSslSocketFactory(), sslConfig.getX509TrustManager());
}
return builder.build().newCall(request);
}
void collectHeader(Request.Builder builder, HttpUrl httpUrl) {
//加载默认Header
Map defaultHeaders = HttpClient.Instance.getDefaultHeaders(httpUrl);
if (CollectionUtils.isNotEmpty(defaultHeaders)) {
for (Map.Entry entry : defaultHeaders.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
}
if (CollectionUtils.isNotEmpty(headers)) {
for (Map.Entry entry : headers.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
}
}
/**
* 构建URL地址
*/
String buildUrl() {
Assert.hasLength(url, "Url must not be null.");
StringBuilder sb = new StringBuilder(url);
if (url.contains("?")) {
sb.append("&");
} else {
sb.append("?");
}
if (CollectionUtils.isNotEmpty(queryParams)) {
for (Map.Entry> entry : queryParams.entrySet()) {
for (String value : entry.getValue()) {
sb.append(entry.getKey()).append("=")
.append(Utils.urlEncode(value)).append("&");
}
}
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
final class CertificateHolder {
InputStream[] certificates;
X509TrustManager trustManager;
InputStream pfxStream;
char[] pfxPwd;
CertificateHolder(InputStream[] certificates, X509TrustManager trustManager,
InputStream pfxStream, char[] pfxPwd) {
this.certificates = certificates;
this.trustManager = trustManager;
this.pfxStream = pfxStream;
this.pfxPwd = pfxPwd;
}
}
final class TimeoutHolder {
int timeout;
TimeUnit timeUnit;
TimeoutHolder(int timeout, TimeUnit timeUnit) {
this.timeout = timeout;
this.timeUnit = timeUnit;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy