com.qiniu.storage.Api Maven / Gradle / Ivy
Show all versions of qiniu-java-sdk Show documentation
package com.qiniu.storage;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import com.qiniu.http.MethodType;
import com.qiniu.http.RequestStreamBody;
import com.qiniu.util.*;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okio.BufferedSink;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
/**
* api 基类,非七牛 Api 请不要使用此接口,此 Api 有业务定制
*/
public class Api {
private final Client client;
private final List interceptors;
/**
* 构造函数
*
* @param client 请求的 Client【必须】
**/
protected Api(Client client) {
this.client = client;
this.interceptors = null;
}
/**
* 构造函数
*
* @param client 请求的 Client 【必须】
* @param config 请求的流程的配置信息
**/
Api(Client client, Config config) {
this(client, Api.createInterceptors(config));
}
/**
* 构造函数
*
* @param client 请求的 Client【必须】
* @param interceptors 请求的拦截器
**/
Api(Client client, Interceptor... interceptors) {
if (client == null) {
client = new Client();
}
this.client = client;
List is = new ArrayList<>();
is.add(new ApiInterceptorDefaultHeader.Builder().build());
if (interceptors != null) {
is.addAll(Arrays.asList(interceptors));
}
Collections.sort(is, new Comparator() {
@Override
public int compare(Interceptor o1, Interceptor o2) {
return o1.priority() - o2.priority();
}
});
// 反转
Collections.reverse(is);
this.interceptors = is;
}
private static Interceptor[] createInterceptors(Config config) {
if (config == null) {
config = new Config.Builder().build();
}
return new Interceptor[]{
new ApiInterceptorAuth.Builder()
.setAuth(config.auth)
.build(),
new ApiInterceptorDebug.Builder()
.setRequestLevel(config.requestDebugLevel)
.setResponseLevel(config.responseDebugLevel)
.build(),
new ApiInterceptorRetryHosts.Builder()
.setHostProvider(config.hostProvider)
.setRetryInterval(config.retryInterval)
.setRetryMax(config.hostRetryMax)
.setRetryCondition(config.retryCondition)
.setHostFreezeCondition(config.hostFreezeCondition)
.setHostFreezeDuration(config.hostFreezeDuration)
.build(),
new ApiInterceptorRetrySimple.Builder()
.setRetryMax(config.singleHostRetryMax)
.setRetryInterval(config.retryInterval)
.setRetryCondition(config.retryCondition)
.build()
};
}
protected com.qiniu.http.Response innerRequest(Request request) throws QiniuException {
if (client == null) {
ApiUtils.throwInvalidRequestParamException("client");
}
MethodType method = request.getMethod();
String url = request.getUrl().toString();
StringMap header = request.getHeader();
RequestBody body = method.hasContent() ? request.getRequestBody() : null;
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
.url(url)
.method(method.toString(), body);
return client.send(requestBuilder, header);
}
protected com.qiniu.http.Response requestByClient(Request request) throws QiniuException {
if (request == null) {
ApiUtils.throwInvalidRequestParamException("request");
}
request.prepareToRequest();
return innerRequest(request);
}
protected com.qiniu.http.Response requestWithInterceptor(Request request) throws QiniuException {
if (request == null) {
ApiUtils.throwInvalidRequestParamException("request");
}
request.prepareToRequest();
if (interceptors == null || interceptors.size() == 0) {
return innerRequest(request);
}
Handler handler = new Handler() {
@Override
public Api.Response handle(Request req) throws QiniuException {
return new Response(innerRequest(req));
}
};
for (Interceptor interceptor : interceptors) {
final Handler h = handler;
final Interceptor i = interceptor;
handler = new Handler() {
@Override
public Api.Response handle(Request req) throws QiniuException {
return i.intercept(req, h);
}
};
}
Response response = handler.handle(request);
return response != null ? response.getResponse() : null;
}
protected Response request(Request request) throws QiniuException {
return new Response(requestWithInterceptor(request));
}
public static final class Config {
public static final int DebugLevelNone = ApiInterceptorDebug.LevelPrintNone;
public static final int DebugLevelNormal = ApiInterceptorDebug.LevelPrintNormal;
public static final int DebugLevelDetail = ApiInterceptorDebug.LevelPrintDetail;
/**
* 鉴权信息
* 注:上传接口鉴权通过 up token 鉴权,不需要设置此参数
**/
private final Auth auth;
/**
* 多个域名切换重试的最大次数
* 当一个域名请求失败,如果符合重试条件,会尝试切换其他域名进行重试
**/
private final int hostRetryMax;
/**
* 单个域名重试的最大次数
* 某个域名的请求失败,如果符合重试条件,会尝试重试
**/
private final int singleHostRetryMax;
/**
* 重试间隔
**/
private final Retry.Interval retryInterval;
/**
* 重试条件
**/
private final Retry.RetryCondition retryCondition;
/**
* 域名冻结条件,域名冻结后在一定时间内不再使用
**/
private final Retry.HostFreezeCondition hostFreezeCondition;
/**
* 重试域名提供对象
**/
private final HostProvider hostProvider;
/**
* 域名冻结时间,单位:毫秒
**/
private final int hostFreezeDuration;
/**
* 请求信息 Debug 等级
* 参考:
* {@link Config#DebugLevelNone}
* {@link Config#DebugLevelNormal}
* {@link Config#DebugLevelDetail}
*
* 注:不再范围内的均按 {@link Config#DebugLevelNone} 处理
**/
private final int requestDebugLevel;
/**
* 响应信息 Debug 等级
* 参考:
* {@link Config#DebugLevelNone}
* {@link Config#DebugLevelNormal}
* {@link Config#DebugLevelDetail}
*
* 注:不再范围内的均按 {@link Config#DebugLevelNone} 处理
**/
private final int responseDebugLevel;
private Config(Auth auth, int hostRetryMax, int singleHostRetryMax, Retry.Interval retryInterval, Retry.RetryCondition retryCondition, Retry.HostFreezeCondition hostFreezeCondition, HostProvider hostProvider, int hostFreezeDuration, int requestDebugLevel, int responseDebugLevel) {
this.auth = auth;
this.hostRetryMax = hostRetryMax;
this.singleHostRetryMax = singleHostRetryMax;
this.retryInterval = retryInterval;
this.retryCondition = retryCondition;
this.hostFreezeCondition = hostFreezeCondition;
this.hostProvider = hostProvider;
this.hostFreezeDuration = hostFreezeDuration;
this.requestDebugLevel = requestDebugLevel;
this.responseDebugLevel = responseDebugLevel;
}
public static final class Builder {
private Auth auth;
private int hostRetryMax;
private int singleHostRetryMax;
private Retry.Interval retryInterval;
private Retry.RetryCondition retryCondition;
private Retry.HostFreezeCondition hostFreezeCondition;
private HostProvider hostProvider;
private int hostFreezeDuration;
private int requestDebugLevel;
private int responseDebugLevel;
public Builder setAuth(Auth auth) {
this.auth = auth;
return this;
}
public Builder setHostRetryMax(int hostRetryMax) {
this.hostRetryMax = hostRetryMax;
return this;
}
public Builder setSingleHostRetryMax(int singleHostRetryMax) {
this.singleHostRetryMax = singleHostRetryMax;
return this;
}
public Builder setRetryInterval(int retryInterval) {
this.retryInterval = Retry.staticInterval(retryInterval);
return this;
}
public Builder setRetryInterval(Retry.Interval retryInterval) {
this.retryInterval = retryInterval;
return this;
}
public Builder setRetryCondition(Retry.RetryCondition retryCondition) {
this.retryCondition = retryCondition;
return this;
}
public Builder setHostFreezeDuration(int hostFreezeDuration) {
this.hostFreezeDuration = hostFreezeDuration;
return this;
}
public Builder setHostProvider(HostProvider hostProvider) {
this.hostProvider = hostProvider;
return this;
}
public Builder setHostFreezeCondition(Retry.HostFreezeCondition hostFreezeCondition) {
this.hostFreezeCondition = hostFreezeCondition;
return this;
}
public Builder setRequestDebugLevel(int requestDebugLevel) {
this.requestDebugLevel = requestDebugLevel;
return this;
}
public Builder setResponseDebugLevel(int responseDebugLevel) {
this.responseDebugLevel = responseDebugLevel;
return this;
}
public Config build() {
return new Config(auth, hostRetryMax, singleHostRetryMax, retryInterval, retryCondition, hostFreezeCondition, hostProvider, hostFreezeDuration, requestDebugLevel, responseDebugLevel);
}
}
}
/**
* api 请求基类
*/
public static class Request implements Cloneable {
/**
* 请求的 scheme
* eg: https
*/
private String scheme;
/**
* 请求的域名
*/
private String host;
/**
* 请求服务的端口号
*/
private int port;
/**
* 请求 url 的 path
*/
private String path;
/**
* 请求 url 的 信息,最终会被按顺序拼接作为 path /Segment0/Segment1
*/
private List pathSegments = new ArrayList<>();
/**
* 请求 url 的 query
* 由 queryInfo 拼接
*/
private String query;
/**
* 请求 url 的 query 信息,最终会被拼接作为 query key0=value0&key1=value1
*/
private List> queryPairs = new ArrayList<>();
/**
* Http 请求方式
*/
private MethodType method = MethodType.GET;
/**
* 请求头
*/
private Map header = new HashMap<>();
/**
* 请求 body
**/
private Request.Body body;
/**
* 请求时,每次从流中读取的数据大小
* 注: body 使用 InputStream 时才有效
*/
private long streamBodySinkSize = 1024 * 10;
/**
* 构造请求对象
*
* @param urlPrefix 请求的 urlPrefix, scheme + host
*/
protected Request(String urlPrefix) {
if (StringUtils.isNullOrEmpty(urlPrefix)) {
return;
}
try {
URL url = new URL(urlPrefix);
this.scheme = url.getProtocol();
this.host = url.getHost();
this.port = url.getPort();
// segment 不包含左边的 /, 截掉左边第一个 /
String segment = url.getPath();
if (segment != null && segment.startsWith("/")) {
segment = segment.substring(1);
}
this.addPathSegment(segment);
String query = url.getQuery();
if (StringUtils.isNullOrEmpty(query)) {
return;
}
String[] queryKVs = query.split("&");
if (queryKVs == null || queryKVs.length == 0) {
return;
}
for (String kv : queryKVs) {
if (StringUtils.isNullOrEmpty(kv)) {
continue;
}
String[] keyValue = kv.split("=", 2);
if (keyValue == null || keyValue.length != 2) {
continue;
}
this.addQueryPair(keyValue[0], keyValue[1]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected Request(String scheme, String host) {
this.scheme = scheme;
this.host = host;
}
/**
* 获取请求的 urlPrefix, scheme + host
* eg: https://upload.qiniu.com
*
* @return urlPrefix
*/
public String getUrlPrefix() {
return scheme + "://" + host;
}
/**
* 获取 请求的 Host
*
* @return Host
* @throws QiniuException 解析 urlPrefix 时的异常
*/
public String getHost() throws QiniuException {
return host;
}
void setHost(String host) {
URL tmpUrl = UrlUtils.parseHost(host);
if (tmpUrl == null) {
this.host = null;
return;
}
this.host = tmpUrl.getHost();
if (tmpUrl.getPort() >= 0) {
this.port = tmpUrl.getPort();
}
}
/**
* 添加 path 信息,注意 path 添加顺序
* 所有的 path item 最终会按照顺序被拼接作为 path
* eg: /item0/item1
*
* @param segment 被添加 path segment
*/
protected void addPathSegment(String segment) {
if (StringUtils.isNullOrEmpty(segment)) {
return;
}
pathSegments.add(segment);
path = null;
}
String getMethodString() {
if (method == null) {
return "GET";
}
return method.toString();
}
MethodType getMethod() {
if (method == null) {
return MethodType.GET;
}
return method;
}
/**
* 获取 url 的 path 信息
*
* @return path 信息
* @throws QiniuException 异常
*/
public String getPath() throws QiniuException {
if (path == null) {
buildPath();
}
return path;
}
/**
* 根据 queryInfo 组装 query 字符串
*
* @throws QiniuException 组装 query 时的异常,一般为缺失必要参数的异常
*/
protected void buildPath() throws QiniuException {
path = StringUtils.join(pathSegments, "/");
if (!path.isEmpty()) {
path = "/" + path;
}
}
/**
* 增加 query 键值对
*
* @param key key
* @param value value
*/
protected void addQueryPair(String key, String value) {
if (StringUtils.isNullOrEmpty(key)) {
return;
}
queryPairs.add(new Pair(key, value));
query = null;
}
/**
* 获取 query 字符串
*
* @return query 字符串
* @throws QiniuException 组装 query 时的异常,一般为缺失必要参数的异常
*/
public String getQuery() throws QiniuException {
if (StringUtils.isNullOrEmpty(query)) {
buildQuery();
}
return query;
}
/**
* 根据 queryInfo 组装 query 字符串
*
* @throws QiniuException 组装 query 时的异常,一般为缺失必要参数的异常
*/
protected void buildQuery() throws QiniuException {
StringBuilder builder = new StringBuilder();
for (Pair pair : queryPairs) {
if (builder.length() > 0) {
builder.append("&");
}
try {
builder.append(URLEncoder.encode(pair.getKey(), "UTF-8"));
if (pair.getValue() != null) {
builder.append("=");
builder.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
}
} catch (Exception e) {
throw new QiniuException(e);
}
}
query = builder.toString();
}
/**
* 设置 Http 请求方式
*
* @param method Http 请求方式
*/
protected void setMethod(MethodType method) {
if (method == null) {
return;
}
this.method = method;
}
/**
* 增加请求头
*
* @param key key
* @param value value
*/
public void addHeaderField(String key, String value) {
if (StringUtils.isNullOrEmpty(key) || StringUtils.isNullOrEmpty(value)) {
return;
}
header.put(key, value);
}
private void removeHeaderField(String key) {
if (StringUtils.isNullOrEmpty(key)) {
return;
}
header.remove(key);
}
/**
* 获取请求头信息
*
* @return 请求头信息
* @throws QiniuException 异常
*/
public StringMap getHeader() throws QiniuException {
StringMap header = new StringMap();
for (String key : this.header.keySet()) {
header.put(key, this.header.get(key));
}
if (body == null || body.contentType == null
|| header.keySet().contains("Content-Type")) {
return header;
}
header.put("Content-Type", body.contentType.toString());
return header;
}
/**
* 构造 header 信息,如果需要设置请求体,子类需要重写
*
* @throws QiniuException 组装 header 时的异常,一般为缺失必要参数的异常
*/
protected void buildHeader() throws QiniuException {
}
/**
* 获取 URL
*
* @return url
* @throws QiniuException 异常
*/
public URL getUrl() throws QiniuException {
if (StringUtils.isNullOrEmpty(scheme)) {
throw QiniuException.unrecoverable("scheme is empty, check if scheme is set or your url format is correct.");
}
if (StringUtils.isNullOrEmpty(host)) {
throw QiniuException.unrecoverable("host is empty, check if host is set or your url format is correct.");
}
try {
String file = "";
String path = getPath();
if (!StringUtils.isNullOrEmpty(path)) {
file += path;
}
String query = getQuery();
if (!StringUtils.isNullOrEmpty(query)) {
file += '?' + query;
}
return new URL(scheme, host, port, file);
} catch (Exception e) {
throw new QiniuException(e);
}
}
/**
* 设置请求体
* 请求数据:在 body 中,从 bodyOffset 开始,获取 bodySize 大小的数据作为请求体
* 此方式配置的 body 支持重试,支持 auth
*
* @param body 请求数据源
* @param offset 请求数据在 body 中的偏移量
* @param size 请求数据大小
* @param contentType 请求数据类型
*/
protected void setBody(byte[] body, int offset, int size, String contentType) {
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
this.body = new Request.Body.BytesBody(body, offset, size, contentType);
}
/**
* 设置请求体
* 此方式配置的 body 不支持重试,不支持 auth
*
* @param body 请求数据源
* @param contentType 请求数据类型
* @param limitSize 最大读取 body 的大小;body 有多余则被舍弃;body 不足则会上传多有 body;
* 如果提前不知道 body 大小,但想上传所有 body,limitSize 设置为 -1 即可;
*/
protected void setBody(InputStream body, String contentType, long limitSize) {
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
Request.Body.InputStreamBody b = new Request.Body.InputStreamBody(body, contentType, limitSize);
b.streamBodySinkSize = streamBodySinkSize;
this.body = b;
}
/**
* 设置表单请求体
* 此方式配置的 body 支持重试,不支持 auth
*
* @param name 表单 name 【必须】
* @param fileName 表单 fileName
* @param fields 表单 fields
* @param body 表单 byte[] 类型 body 【必须】
* @param contentType 表单 body 的 Mime type
**/
protected void setFormBody(String name, String fileName, StringMap fields, byte[] body, String contentType) {
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
this.body = new Request.Body.FormBody(name, fileName, fields, body, contentType);
}
/**
* 设置表单请求体
* 此方式配置的 body 支持重试,不支持 auth
*
* @param name 表单 name 【必须】
* @param fileName 表单 fileName
* @param fields 表单 fields
* @param body 表单 File 类型 body 【必须】
* @param contentType 表单 body 的 Mime type
**/
protected void setFormBody(String name, String fileName, StringMap fields, File body, String contentType) {
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
this.body = new Request.Body.FormBody(name, fileName, fields, body, contentType);
}
/**
* 使用 streamBody 时,每次读取 streamBody 的大小,读取后发送
* 默认:{@link Api.Request#streamBodySinkSize}
* 相关:{@link RequestStreamBody#writeTo(BufferedSink) sinkSize}
*
* @param streamBodySinkSize 每次读取 streamBody 的大小
* @return Request
*/
public Request setStreamBodySinkSize(long streamBodySinkSize) {
this.streamBodySinkSize = streamBodySinkSize;
if (body != null && body instanceof Request.Body.InputStreamBody) {
((Body.InputStreamBody) body).streamBodySinkSize = streamBodySinkSize;
}
return this;
}
/**
* 是否有请求体
*
* @return 是否有请求体
*/
public boolean hasBody() {
return body != null;
}
private RequestBody getRequestBody() {
if (!hasBody()) {
return Body.BytesBody.empty().get();
}
if (body instanceof Body.InputStreamBody) {
((Body.InputStreamBody) body).streamBodySinkSize = streamBodySinkSize;
}
return body.get();
}
byte[] getBytesBody() {
if (!hasBody()) {
return null;
}
return body.getBytes();
}
/**
* 构造 body 信息,如果需要设置请求体,子类需要重写
*
* @throws QiniuException 异常
*/
protected void buildBodyInfo() throws QiniuException {
}
boolean canRetry() {
if (!hasBody()) {
return true;
}
return body.canReset();
}
/**
* 准备上传 做一些参数检查 以及 参数构造
*
* @throws QiniuException 异常,一般为参数缺失
*/
protected void prepareToRequest() throws QiniuException {
buildPath();
buildQuery();
buildHeader();
buildBodyInfo();
}
public Request clone() {
try {
Request clone = (Request) super.clone();
clone.pathSegments = new ArrayList<>(pathSegments);
clone.queryPairs = new ArrayList<>(queryPairs);
clone.header = new HashMap<>(header);
return clone;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
protected static class Pair {
/**
* Key of this Pair
.
*/
private K key;
/**
* Gets the key for this pair.
*
* @return key for this pair
*/
K getKey() {
return key;
}
/**
* Value of this this Pair
.
*/
private V value;
/**
* Gets the value for this pair.
*
* @return value for this pair
*/
V getValue() {
return value;
}
/**
* Creates a new pair
*
* @param key The key for this pair
* @param value The value to use for this pair
*/
protected Pair(K key, V value) {
this.key = key;
this.value = value;
}
/**
* String
representation of this
* Pair
.
*
* The default name/value delimiter '=' is always used.
*
* @return String
representation of this Pair
*/
@Override
public String toString() {
return key + "=" + value;
}
/**
* Generate a hash code for this Pair
.
*
* The hash code is calculated using both the name and
* the value of the Pair
.
*
* @return hash code for this Pair
*/
@Override
public int hashCode() {
// name's hashCode is multiplied by an arbitrary prime number (13)
// in order to make sure there is a difference in the hashCode between
// these two parameters:
// name: a value: aa
// name: aa value: a
return key.hashCode() * 13 + (value == null ? 0 : value.hashCode());
}
/**
* Test this Pair
for equality with another
* Object
.
*
* If the Object
to be tested is not a
* Pair
or is null
, then this method
* returns false
.
*
* Two Pair
s are considered equal if and only if
* both the names and values are equal.
*
* @param o the Object
to test for
* equality with this Pair
* @return true
if the given Object
is
* equal to this Pair
else false
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof Pair) {
Pair pair = (Pair) o;
if (!Objects.equals(key, pair.key)) return false;
if (!Objects.equals(value, pair.value)) return false;
return true;
}
return false;
}
}
private abstract static class Body {
protected final MediaType contentType;
protected Body(String contentType) {
this.contentType = MediaType.parse(contentType);
}
protected boolean canReset() {
return false;
}
protected void reset() throws QiniuException {
throw QiniuException.unrecoverable("not support reset");
}
protected abstract RequestBody get();
protected byte[] getBytes() {
return null;
}
private static final class BytesBody extends Body {
private final byte[] bytes;
private final int offset;
private final int length;
private static BytesBody empty() {
return new BytesBody(new byte[0], 0, 0, Client.DefaultMime);
}
private BytesBody(byte[] bytes, int offset, int length, String contentType) {
super(contentType);
this.bytes = bytes;
this.offset = offset;
this.length = length;
}
@Override
protected boolean canReset() {
return true;
}
@Override
protected void reset() throws QiniuException {
}
@Override
protected RequestBody get() {
return RequestBody.create(contentType, bytes, offset, length);
}
@Override
public byte[] getBytes() {
if (bytes == null || bytes.length == 0) {
return new byte[]{};
}
if (offset == 0 && length == bytes.length) {
return bytes;
}
return Arrays.copyOfRange(bytes, offset, offset + length);
}
}
private static final class InputStreamBody extends Body {
private final InputStream stream;
private final long limitSize;
private long streamBodySinkSize = 1024 * 10;
private InputStreamBody(InputStream stream, String contentType, long limitSize) {
super(contentType);
this.stream = stream;
this.limitSize = limitSize;
}
@Override
protected RequestBody get() {
RequestStreamBody b = new RequestStreamBody(stream, contentType, limitSize);
b.setSinkSize(streamBodySinkSize);
return b;
}
}
private static final class FormBody extends Body {
private final String name;
private final String fileName;
private final StringMap fields;
private final byte[] bytes;
private final File file;
private FormBody(String name, String fileName, StringMap fields, byte[] body, String contentType) {
super(contentType);
this.name = name;
this.fileName = fileName;
this.fields = fields;
this.bytes = body;
this.file = null;
}
private FormBody(String name, String fileName, StringMap fields, File body, String contentType) {
super(contentType);
this.name = name;
this.fileName = fileName;
this.fields = fields;
this.bytes = null;
this.file = body;
}
@Override
protected boolean canReset() {
return true;
}
@Override
protected void reset() throws QiniuException {
}
@Override
protected RequestBody get() {
RequestBody body = null;
if (bytes != null) {
body = RequestBody.create(contentType, bytes);
} else if (file != null) {
body = RequestBody.create(contentType, file);
} else {
body = RequestBody.create(contentType, new byte[0]);
}
final MultipartBody.Builder b = new MultipartBody.Builder();
if (!StringUtils.isNullOrEmpty(name)) {
b.addFormDataPart(name, fileName, body);
}
if (fields != null) {
fields.forEach(new StringMap.Consumer() {
@Override
public void accept(String key, Object value) {
b.addFormDataPart(key, value.toString());
}
});
}
b.setType(MediaType.parse("multipart/form-data"));
return b.build();
}
}
}
}
/**
* api 响应基类
*/
public static class Response {
/**
* 响应数据
*/
private StringMap dataMap;
/**
* 响应数据
*/
private Object[] dataArray;
/**
* 原响应结果
*/
private final com.qiniu.http.Response response;
/**
* 构建 Response
*
* @param response com.qiniu.http.Response
* @throws QiniuException 解析 data 异常
*/
protected Response(com.qiniu.http.Response response) throws QiniuException {
this.response = response;
if (response == null) {
return;
}
String bodyString = response.bodyString();
try {
if (bodyString.startsWith("[")) {
this.dataArray = Json.decodeArray(bodyString);
} else {
this.dataMap = Json.decode(bodyString);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取 response data array,当 response body 为 json,且为数组时有值
*
* @return data array
*/
public Object[] getDataArray() {
return dataArray;
}
/**
* 获取 response data map,当 response body 为 json,且为键值对时有值
*
* @return data map
*/
public StringMap getDataMap() {
return dataMap;
}
/**
* 获取 com.qiniu.http.Response,信息量更大
*
* @return com.qiniu.http.Response
*/
public com.qiniu.http.Response getResponse() {
return response;
}
/**
* 请求是否成功
*
* @return 是否成功
*/
public boolean isOK() {
return response.isOK();
}
/**
* 根据 keyPath 读取 data map 中对应的 String value
* eg:
* dataMap: {"key00" : { "key10" : "key10_value"}}
* keyPath = new String[]{"key00", "key10"}
* 调用方法后 value = key10_value
*
* @param keyPath keyPath
* @return keyPath 对应的 String value
*/
public String getStringValueFromDataMap(String... keyPath) {
Object value = getValueFromDataMap(keyPath);
if (value == null) {
return null;
}
return value.toString();
}
/**
* 根据 keyPath 读取 data map 中对应的 Long value
* eg:
* dataMap: {"key00" : { "key10" : 10}}
* keyPath = new String[]{"key00", "key10"}
* 调用方法后 value = 10
*
* @param keyPath keyPath
* @return keyPath 对应的 Long value
*/
public Long getLongValueFromDataMap(String... keyPath) {
Object value = getValueFromDataMap(keyPath);
return ApiUtils.objectToLong(value);
}
/**
* 根据 keyPath 读取 data map 中对应的 Integer value
* eg:
* dataMap: {"key00" : { "key10" : 10}}
* keyPath = new String[]{"key00", "key10"}
* 调用方法后 value = 10
*
* @param keyPath keyPath
* @return keyPath 对应的 Integer value
*/
public Integer getIntegerValueFromDataMap(String... keyPath) {
Object value = getValueFromDataMap(keyPath);
return ApiUtils.objectToInteger(value);
}
/**
* 根据 keyPath 读取 data map 中对应的 value
* eg:
* dataMap: {"key00" : { "key10" : "key10_value"}}
* keyPath = new String[]{"key00", "key10"}
* 调用方法后 value = key10_value
*
* @param keyPath keyPath
* @return keyPath 对应的 value
*/
public Object getValueFromDataMap(String... keyPath) {
if (dataMap == null) {
return null;
}
return ApiUtils.getValueFromMap(dataMap.map(), keyPath);
}
}
interface Handler {
Response handle(Request request) throws QiniuException;
}
abstract static class Interceptor {
static final int PriorityDefault = 100;
static final int PriorityRetryHosts = 200;
static final int PriorityRetrySimple = 300;
static final int PrioritySetHeader = 400;
static final int PriorityNormal = 500;
static final int PriorityAuth = 600;
static final int PriorityDebug = 700;
/**
* 拦截器,优先级,越小优先级越高
*
* 默认:{@link Interceptor#PriorityNormal}
**/
int priority() {
return PriorityNormal;
}
/**
* 拦截方法
**/
abstract Api.Response intercept(Api.Request request, Handler handler) throws QiniuException;
}
}