
com.alibaba.csb.sdk.HttpCaller Maven / Gradle / Ivy
package com.alibaba.csb.sdk;
import com.alibaba.csb.sdk.internel.DiagnosticHelper;
import com.alibaba.csb.sdk.internel.HttpClientConnManager;
import com.alibaba.csb.sdk.internel.HttpClientHelper;
import com.alibaba.csb.sdk.security.SignUtil;
import com.alibaba.csb.sdk.security.SpasSigner;
import com.alibaba.csb.trace.TraceData;
import com.alibaba.csb.utils.IPUtils;
import com.alibaba.csb.utils.LogUtils;
import com.alibaba.csb.utils.TraceIdUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import java.io.*;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* SDK工具类,用来向服务端发送HTTP请求,请求支持POST/GET方式.
* 如果提供了AccessKey和SecurityKey参数信息,它能够在内部将请求消息进行签名处理,然后由CSB服务端进行验证.
*
*
*
* {@code
* import com.alibaba.csb.sdk.HttpCaller;
* import com.alibaba.csb.sdk.HttpCallerException;
* ...
*
* (1) 直接调用方式 (已过期,不推荐)
*
* Map params = new HashMap();
*
* Object smd = ... // 一个具体的复杂对象
* if (smd != null) {
* String data = JSON.toJSONString(smd); //转换为JSON String
* params.put("data", data);
* }
*
* // -- Tip: 如果调用者无法获得复杂对象参数类,则可以使用全map的方式设置json串,举例,对于json串
* // {"f1":{"f11":"v11", "f12":["v121","v122"]}, "f2":"wiseking"}
* // 它是可以通过如下的方式进行转换而来
* Map map = new HashMap();
*
* Map mapF1 = new HashMap();
* mapF1.put("f11", "v11");
* mapF1.put("f12", Arrays.asList("v121","v122"));
* map.put("f1", mapF1);
*
* map.put("f2", "wiseking");
* String jsonData = JSON.toJSONString(map);
* // -- Tip End
*
* params.put("name", "abcd"); //普通的串对象
* params.put("password", "abcd"); //普通的串对象
*
*
* String requestURL = "http://gateway.abc.com:8086/CSB";
* String API_NAME = "login_system";
* String version = "1.0.0";
* String ak = "xxxxxx";
* String sk = "xxxxxx"; //用户安全校验的签名密钥对
*
* try {
* String result = HttpCaller.doPost(requestURL, API_NAME, version, params, ak, sk);
*
* if (result != null) {
* //返回结果处理, 如转换为JSON对象
* ...
* }
* } catch (HttpCallerException ie) {
* //print error
* }}
*
* (2) 也可以使用第二种Builder的方式构造调用参数,然后进行调用 (推荐用法)
* import com.alibaba.csb.sdk.HttpParameters;
* import com.alibaba.csb.sdk.HttpCaller;
* import com.alibaba.csb.sdk.HttpCallerException;
*
* HttpParameters.Builder builder = HttpParameters.newBuilder();
*
* builder.requestURL("http://broker-ip:8086/CSB?arg0=123") // 设置请求的URL
* .api("test") // 设置服务名
* .version("1.0.0") // 设置版本号
* .method("get") // 设置调用方式, get/post
* .accessKey("ak").secretKey("sk"); // 设置accessKey 和 设置secretKey
*
* // 设置请求参数
* builder.putParamsMap("key1", "value1");
* builder.putParamsMap("key2", "{\"a\":value1}"); // json format value
*
* //设置请求调用方式
* builder.method("get");
*
* //设置透传的HTTP Headers
* builder.putHeaderParamsMap("header1", "value1");
* builder.putHeaderParamsMap("header2", "value2");
*
* //进行调用 返回结果
* String result = null;
* try {
* result = HttpCaller.invoke(builder.build());
* } catch (HttpCallerException e) {
* // error process
* }
*
* try {
* // 重启设置请求参数
* builder.clearParamsMap();
* builder.putParamsMap("key1", "value1---new");
* builder.putParamsMap("key2", "{\"a\":\"value1-new\"}");
*
* // 使用post方式调用
* builder.method("post");
* HttpCaller.invoke(builder.build());
* } catch (HttpCallerException e) {
* // error process
* }
*
* (3) 如果使用json或者bytes内容的作为http body,使用下面的方法
*
* //构造ContentBody对象
* ContentBody cb = new ContentBody(jsonObject.toSring());
* //或者
* cb = new ContentBody(file2bytes);
*
* //ContentBody传递,要求使用post方式进行调用
* //如果需要传递请求参数 可以拼接到请求URL中,或者设置paramsMap参数由SDK内部进行拼接
* HttpParameters.Builder builder = HttpParameters.newBuilder();
* builder.requestURL("http://broker-ip:8086/CSB?arg0=123") // 设置请求的URL,可以拼接URL请求参数
* .api("test") // 设置服务名
* .version("1.0.0") // 设置版本号
* .method("post") // 设置调用方式, 必须为 post
* .accessKey("ak").secretKey("sk"); // 设置accessKey 和 设置secretKey
*
* builder.contentBody(cb);
*
* //进行调用,返回结果
* String result = null;
* try {
* result = HttpCaller.invoke(builder.build());
* } catch (HttpCallerException e) {
* // error process
* }
*
*
* 高级功能
* 1. 设置代理地址
* String proxyHost = "...";
* int proxyPort = ...;
* HttpCaller.setProxyHost(proxyHost, proxyPort, null); //注意:本次设置只对本线程起作用
* ...
* HttpCaller.doPost(), doGet() or invoke();
*
* 2. 关于连接参数的设置:
* a. 可以为http/https设置以下的全局性系统参数:
* -Dhttp.caller.connection.max 设置连接池的最大连接数,默认是200
* -Dhttp.caller.connection.timeout 设置连接超时时间(毫秒),默认是-1, 永不超时
* -Dhttp.caller.connection.so.timeout 设置读取超时时间(毫秒),默认是-1, 永不超时
* -Dhttp.caller.connection.cr.timeout 设置从连接池获取连接实例的超时(毫秒),默认是-1, 永不超时
* -Dhttp.caller.connection.async 设置使用nio,默认fasle:同步io,true:nio
* -Dhttp.caller.connection.keepalive.timeout 长连接超时时间(秒),默认75
* -Dhttp.caller.skip.connection.pool 如何设置为true,则不使用连接池。默认行为是false,使用连接池(支持长连接)
* b. 也可以使用下面的方法设置以上的某一个或者多个参数:
* Map sysParams = new HashMap();
* sysParams.put("http.caller.connection.timeout","3000"); //设置连接超时为3秒
* HttpCaller.setConnectionParams(sysParams); //注意:本次设置只对本线程起作用
* ...
* HttpCaller.doPost(), doGet() or invoke();
* 3. 设置debug:
* -Dhttp.caller.DEBUG=true
*
*
* @author Alibaba Middleware CSB Team
* @author [email protected]
* @since 2016
*/
public class HttpCaller {
protected static boolean warmupFlag = false;
protected static final String RESTFUL_PATH_SIGNATURE_KEY = "csb_restful_path_signature_key";
protected static final String DEFAULT_RESTFUL_PROTOCOL_VERSION = "1.0";
protected static final String RESTFUL_PROTOCOL_VERION_KEY = "restful_protocol_version";
// TODO: must set truststore for ssl
public static final String trustCA = System.getProperty("http.caller.ssl.trustca");
public static final String DEFAULT_CHARSET = HTTP.UTF_8;
public static final String GZIP = "gzip";
protected static String defaultAK = null;
protected static String defaultSK = null;
protected static ThreadLocal toCurlCmd = new ThreadLocal();
protected static ThreadLocal toHttpRequest = new ThreadLocal();
protected static ThreadLocal proxyConfigThreadLocal = new ThreadLocal();
protected static final RequestConfig.Builder requestConfigBuilder = HttpClientConnManager.createConnBuilder();
protected static final ThreadLocal requestConfigBuilderLocal = new ThreadLocal();
protected static AtomicReference BIZ_ID_KEY = new AtomicReference();
public static final long TOTAL_FILE_SIZE;
static {
//默认15M
TOTAL_FILE_SIZE = Integer.getInteger("csb_httpAttachmentTotalMBSize", 64) * 1024 * 1024;
}
protected HttpCaller() {
}
/**
* init bizIdKey
*
* @param bizIdKey
*/
public static void bizIdKey(String bizIdKey) {
BIZ_ID_KEY.compareAndSet(null, bizIdKey);
}
/**
* get bizIdkey
*
* @return
*/
public static String bizIdKey() {
String bizIdKey = BIZ_ID_KEY.get();
return bizIdKey == null ? CsbSDKConstants.BIZID_KEY : bizIdKey;
}
/**
* 加载HttpSDK所需要的类 (如,签名相关的)
*
* 注意:这是一个高时间代价的启动方法,建议在整个JVM范围内,在使用HttpCaller调用具体的服务前,调用且只调用一次
*/
public static synchronized void warmup() {
if (warmupFlag) {
return;
}
SignUtil.warmup();
warmupFlag = true;
}
/**
* 为接下来的调用设置代理参数。 注意:本次设置只对本线程起作用
*
* @param hostname
* @param port
* @param scheme 如果设置为null时, scheme为 "http"
*/
public static void setProxyHost(final String hostname, final int port, final String scheme) {
proxyConfigThreadLocal.set(new HttpHost(hostname, port, scheme));
}
/**
* 为接下来的调用设置新的连接参数。 注意:本次设置只对本线程起作用
*
* @param params
*/
public static void setConnectionParams(Map params) {
if (params == null || params.size() == 0) {
requestConfigBuilderLocal.set(requestConfigBuilder);
} else {
requestConfigBuilderLocal.set(HttpClientConnManager.createConnBuilder(params));
}
}
private static RequestConfig getRequestConfig() {
RequestConfig.Builder rcBuilder = null;
if (requestConfigBuilderLocal.get() == null) {
rcBuilder = requestConfigBuilder;
} else {
rcBuilder = requestConfigBuilderLocal.get();
}
rcBuilder.setProxy(proxyConfigThreadLocal.get());
return rcBuilder.build();
}
/**
* 当参数flag设置为true时, 使当前调用doGet/doPost的线程不做真实的调用而是生成curl命令请求串返回
*
* @param flag
*/
public static void setCurlResponse(boolean flag) {
toCurlCmd.set(true);
}
private static boolean isCurlResponse() {
return toCurlCmd.get() != null && toCurlCmd.get() == true;
}
public static void setToHttpRequest(boolean flag) {
toHttpRequest.set(true);
}
/**
* 一次设置,只能读取一次,避免上下文影响
*/
private static boolean isToHttpRequest() {
try {
return toHttpRequest.get() != null && toHttpRequest.get() == true;
} finally {
toHttpRequest.remove();
}
}
/**
* 设置默认的AK/SK, 以后发送请求可以使用该默认值进行签名,
*
* 注意: 这个方法设置静态的accessKey,secretKey变量到HttpCaller中,所以会影响所有的使用HttpCaller的方法,即
* 如果调用方法不指定AK/SK, 会使用这里本方法设置的AK/SK.
*
* @param accessKey 访问key
* @param secretKey 安全key
*/
public static void setCredential(String accessKey, String secretKey) {
defaultAK = accessKey;
defaultSK = secretKey;
}
/**
* 把一个串的字符集从旧的的字符集到一个新的字符集合, 一个辅助方法,主要用于HTTP调用返回值的转换
*
* @param result 要装换的字符串
* @param OldcharsetName 源编码方式
* @param charsetName 目标编码方式
* @return 返回转换后的字符串
* @throws HttpCallerException
*/
public static String changeCharset(String result, String OldcharsetName, String charsetName)
throws HttpCallerException {
if (result == null) {
return result;
}
try {
return new String(result.getBytes(OldcharsetName), charsetName);
} catch (UnsupportedEncodingException e) {
throw new HttpCallerException(e);
}
}
/**
* 把一个串的字符集从"ISO-8859-1"改变到"UTF-8", 一个辅助方法,主要用于HTTP调用返回值的转换
*
* @param result 要装换的字符串
* @return 返回转换后的字符串
* @throws HttpCallerException
*/
public static String changeCharset(String result) throws HttpCallerException {
return changeCharset(result, "ISO-8859-1", DEFAULT_CHARSET);
}
/**
* 方法说明: 使用GET的方式发送请求服务,如果设置过默认AK/SK, 则使用它们将请求消息进行签名
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB
* @param apiName API名字(服务名)
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 1. 新版本(1.0.2.1+)的CSB服务需要定义服务版本参数
* 2. 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doGet(String requestURL, String apiName, Map paramsMap)
throws HttpCallerException {
return doGet(requestURL, apiName, paramsMap, defaultAK, defaultSK);
}
/**
* 方法说明: 使用GET的方式发送请求服务,并使用指定的AK/SK将请求消息进行签名
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8080/test/abc
* @param apiName API名字(服务名)
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @param accessKey 访问key
* @param secretKey 安全keyx
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doGet(String requestURL, String apiName, Map paramsMap, String accessKey,
String secretKey) throws HttpCallerException {
return doGet(requestURL, apiName, null, paramsMap, accessKey, secretKey);
}
/**
* 使用GET的方式发送请求服务,并使用指定的AK/SK将请求消息进行签名
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值,如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param accessKey 访问key
* @param secretKey 安全key
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doGet(String requestURL, String apiName, String version, Map paramsMap,
String accessKey, String secretKey) throws HttpCallerException {
return doGet(requestURL, apiName, version, paramsMap, accessKey, secretKey, null, null);
}
/**
* 使用GET的方式发送请求服务,并使用指定的AK/SK将请求消息进行签名
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值,如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param accessKey 访问key
* @param secretKey 安全key
* @param signImpl 签名算法实现类名
* @param verifySignImpl 验签算法实现类名
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doGet(String requestURL, String apiName, String version, Map paramsMap,
String accessKey, String secretKey, String signImpl, String verifySignImpl) throws HttpCallerException {
HttpParameters hp = HttpParameters.newBuilder().requestURL(requestURL).api(apiName).version(version).putParamsMapAll(paramsMap)
.accessKey(accessKey).secretKey(secretKey).signImpl(signImpl).verifySignImpl(verifySignImpl)
.build();
return doGet(hp, null).getResponseStr();
}
/**
* 获取签名串
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值,如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param accessKey 访问key
* @param secretKey 安全key
* @return 发送CSB请求需要增加的httpHeader,包含签名串等
*/
public static Map getCsbHeaders(String requestURL, String apiName, String version, Map paramsMap, String accessKey, String secretKey) throws HttpCallerException {
return getCsbHeaders(requestURL, apiName, version, paramsMap, accessKey, secretKey, null, null, null, SpasSigner.SigningAlgorithm.HmacSHA1.name());
}
/**
* 获取签名串
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值,如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param accessKey 访问key
* @param secretKey 安全key
* @return 发送CSB请求需要增加的httpHeader,包含签名串等
*/
public static Map getCsbHeaders(String requestURL, String apiName, String version, Map paramsMap, String accessKey, String secretKey, String charset) throws HttpCallerException {
return getCsbHeaders(requestURL, apiName, version, paramsMap, accessKey, secretKey, null, null, charset, SpasSigner.SigningAlgorithm.HmacSHA1.name());
}
/**
* 获取签名串
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值,如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param accessKey 访问key
* @param secretKey 安全key
* @param signImpl 签名算法实现类名
* @param verifySignImpl 验签算法实现类名
* @param charset 字符集
* @param signAlgothrim 签名算法
* @return 发送CSB请求需要增加的httpHeader,包含签名串等
*/
public static Map getCsbHeaders(String requestURL, String apiName, String version, Map paramsMap
, String accessKey, String secretKey, String signImpl, String verifySignImpl
, String charset, String signAlgothrim) throws HttpCallerException {
Map> urlParamsMap = HttpClientHelper.parseUrlParamsMap(requestURL, charset, true);
HttpClientHelper.mergeParams(urlParamsMap, paramsMap);
return HttpClientHelper.newParamsMap(urlParamsMap, apiName, version, accessKey, secretKey,
true, false, null, null, signImpl, verifySignImpl, signAlgothrim);
}
private static HttpReturn doGet(HttpParameters hp, Map extSignHeadersMap) throws HttpCallerException {
if (!hp.getHeaderParamsMap().containsKey(CsbSDKConstants.TRACEID_KEY)) {
hp.getHeaderParamsMap().put(TraceData.TRACEID_KEY, TraceIdUtils.generate());
hp.getHeaderParamsMap().put(TraceData.RPCID_KEY, TraceData.RPCID_DEFAULT);
}
final String requestURL = hp.getRequestUrl();
String apiName = hp.getApi();
String version = hp.getVersion();
Map> paramsMap = hp.getParamsMap();
String accessKey = hp.getAccessKey();
String secretKey = hp.getSecretkey();
String signAlgothrim = hp.getSignAlgorithm();
Map directParamsMap = hp.getHeaderParamsMap();
String restfulProtocolVersion = hp.getRestfulProtocolVersion();
HttpReturn ret = new HttpReturn();
ret.diagnosticFlag = hp.isDiagnostic();
long startT = System.currentTimeMillis();
long initT = startT;
DiagnosticHelper.setStartTime(ret, initT);
HttpClientHelper.validateParams(apiName, accessKey, secretKey, paramsMap);
String charset = hp.getContentType() == null || hp.getContentType().getCharset() == null ? null : hp.getContentType().getCharset().name();
Map> urlParamsMap = HttpClientHelper.parseUrlParamsMap(requestURL, charset, true);
HttpClientHelper.mergeParamsList(urlParamsMap, paramsMap);
if (SdkLogger.isLoggable()) {
SdkLogger.print("--+++ prepare params costs = " + (System.currentTimeMillis() - startT) + " ms ");
}
startProcessRestful(requestURL, restfulProtocolVersion, urlParamsMap);
StringBuilder signDiagnosticInfo = DiagnosticHelper.getSignDiagnosticInfo(ret);
Map headerParamsMap = HttpClientHelper.newParamsMap(urlParamsMap, apiName, version, accessKey, secretKey, hp.isTimestamp()
, hp.isNonce(), extSignHeadersMap, signDiagnosticInfo, hp.getSignImpl(), hp.getVerifySignImpl(), signAlgothrim);
if (hp.getContentType() != null) {
headerParamsMap.put("Content-Type", hp.getContentType().toString());
}
DiagnosticHelper.setSignDiagnosticInfo(ret, signDiagnosticInfo);
endProcessRestful(restfulProtocolVersion, urlParamsMap, headerParamsMap);
String newRequestURL = HttpClientHelper.generateAsEncodeRequestUrl(requestURL, charset, urlParamsMap);
if (isCurlResponse()) {
StringBuffer curl = new StringBuffer("curl ");
curl.append(HttpClientHelper.genCurlHeaders(directParamsMap));
curl.append(HttpClientHelper.genCurlHeaders(headerParamsMap));
curl.append(" -k ");
curl.append("\"").append(newRequestURL).append("\"");
ret.response = curl.toString();
return ret;
}
if (isToHttpRequest()) { //根据请求消息,生成http请求内容。目前使用在控制台发送测试服务消息,通过命令通道转发
return new HttpReturn(newRequestURL, directParamsMap, headerParamsMap);
}
DiagnosticHelper.calcRequestSize(ret, newRequestURL, null, null);
HttpGet httpGet = new HttpGet(newRequestURL);
httpGet.setConfig(getRequestConfig());
// first step to set the direct http headers
if (directParamsMap != null)
HttpClientHelper.setHeaders(httpGet, directParamsMap);
// normal headers have the chance to overwrite the direct headers.
HttpClientHelper.setHeaders(httpGet, headerParamsMap);
DiagnosticHelper.setRequestHeaders(ret, httpGet.getAllHeaders());
String msg = null;
try {
ret = doHttpReq(requestURL, httpGet, ret);
DiagnosticHelper.setEndTime(ret, System.currentTimeMillis());
DiagnosticHelper.setInvokeTime(ret, System.currentTimeMillis() - initT);
return ret;
} catch (HttpCallerException e) {
msg = e.getMessage();
throw e;
} finally {
log(hp, startT, requestURL, ret, msg);
if (SdkLogger.isLoggable()) {
SdkLogger.print("-- total = " + (System.currentTimeMillis() - initT) + " ms ");
}
}
}
private static void endProcessRestful(String restfulProtocolVersion, Map> urlParamsMap, Map headerParamsMap) {
if (DEFAULT_RESTFUL_PROTOCOL_VERSION.equals(restfulProtocolVersion)) {
urlParamsMap.remove(RESTFUL_PATH_SIGNATURE_KEY);
headerParamsMap.put(RESTFUL_PROTOCOL_VERION_KEY, DEFAULT_RESTFUL_PROTOCOL_VERSION);
}
}
private static void startProcessRestful(String requestURL, String restfulProtocolVersion, Map> urlParamsMap) throws HttpCallerException {
if (DEFAULT_RESTFUL_PROTOCOL_VERSION.equals(restfulProtocolVersion)) {
String path = HttpClientHelper.getUrlPathInfo(requestURL);
if (path == null) {
throw new HttpCallerException("this request is restful but the request path is null !");
}
List values = new ArrayList();
values.add(path);
urlParamsMap.put(RESTFUL_PATH_SIGNATURE_KEY, values);
}
}
private static boolean isSSLProtocol(String requestUrl) {
if (requestUrl == null)
return false;
if (requestUrl.trim().toLowerCase().startsWith("https://")) {
return true;
}
return false;
}
private static CloseableHttpClient createSyncHttpClient(String requestURL) throws HttpCallerException {
CloseableHttpClient httpClient = null;
if (isSSLProtocol(requestURL)) {
try {
httpClient = HttpClients.custom().setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
return true;
}
}).build()).setSSLHostnameVerifier(new org.apache.http.conn.ssl.NoopHostnameVerifier()).build();
} catch (KeyManagementException e) {
throw new HttpCallerException(e);
} catch (NoSuchAlgorithmException e) {
throw new HttpCallerException(e);
} catch (KeyStoreException e) {
throw new HttpCallerException(e);
}
} else {
httpClient = HttpClients.createDefault();
}
return httpClient;
}
private static CloseableHttpAsyncClient createAsyncHttpClient(String requestURL) throws HttpCallerException {
CloseableHttpAsyncClient httpClient = null;
if (isSSLProtocol(requestURL)) {
try {
httpClient = HttpAsyncClients.custom().setSSLHostnameVerifier(new org.apache.http.conn.ssl.NoopHostnameVerifier()).setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
}).build()).build();
} catch (KeyManagementException e) {
throw new HttpCallerException(e);
} catch (NoSuchAlgorithmException e) {
throw new HttpCallerException(e);
} catch (KeyStoreException e) {
throw new HttpCallerException(e);
}
} else {
httpClient = HttpAsyncClients.createDefault();
}
httpClient.start();
return httpClient;
}
/**
* 以GET的方式发送URL请求
*
* @param requestURL 请求的服务URL, 如:"http://abc.com:8086/CSB?name=test&value=123"
* @return 返回的JSON串
* @throws HttpCallerException
*/
public static String doGet(String requestURL) throws HttpCallerException {
HttpGet httpGet = new HttpGet(requestURL);
httpGet.setConfig(getRequestConfig());
HttpClientHelper.printDebugInfo("requestURL=" + requestURL);
return doHttpReq(requestURL, httpGet, null).getResponseStr();
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 1. 新版本的CSB服务需要定义服务版本参数
* 2. 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, Map paramsMap)
throws HttpCallerException {
return doPost(requestURL, apiName, null, paramsMap);
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL: 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName: API名字(服务名)
* @param version: API版本号
* @param paramsMap: 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, String version, Map paramsMap)
throws HttpCallerException {
return doPost(requestURL, apiName, version, paramsMap, defaultAK, defaultSK);
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @param accessKey 访问key
* @param secretKey 安全key
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, Map paramsMap, String accessKey,
String secretKey) throws HttpCallerException {
return doPost(requestURL, apiName, paramsMap, accessKey, secretKey, null, null);
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @param accessKey 访问key
* @param secretKey 安全key
* @param signImpl 签名算法实现类名
* @param verifySignImpl 验签算法实现类名
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, Map paramsMap, String accessKey,
String secretKey, String signImpl, String verifySignImpl) throws HttpCallerException {
return doPost(requestURL, apiName, null, paramsMap, accessKey, secretKey, signImpl, verifySignImpl);
}
/**
* 使用POST方式调用HTTP服务, 可以同时支持NameValuePair请求参数(拼接到请求URL中),并且传递contentBody
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param cb 直接设置contentBody, 内容可以是json串 或者 byte[]
* @param accessKey 访问key
* @param secretKey 安全key
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, String version, ContentBody cb, String accessKey,
String secretKey) throws HttpCallerException {
return doPost(requestURL, apiName, version, cb, accessKey, secretKey, null, null);
}
/**
* 使用POST方式调用HTTP服务, 可以同时支持NameValuePair请求参数(拼接到请求URL中),并且传递contentBody
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB/abc, 如果URL里的请求参数有特殊字符(如 '&'),需要先将次值进行URL Encode处理
* @param apiName API名字(服务名)
* @param version API版本号
* @param cb 直接设置contentBody, 内容可以是json串 或者 byte[]
* @param accessKey 访问key
* @param secretKey 安全key
* @param signImpl 签名算法实现类名
* @param verifySignImpl 验签算法实现类名
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, String version, ContentBody cb, String accessKey,
String secretKey, String signImpl, String verifySignImpl) throws HttpCallerException {
HttpParameters hp = HttpParameters.newBuilder().requestURL(requestURL).api(apiName).version(version)
.contentBody(cb).accessKey(accessKey).secretKey(secretKey).signImpl(signImpl).verifySignImpl(verifySignImpl)
.build();
return doPost(hp, null).getResponseStr();
}
/**
* 所有doPost的真正入口参数,httppost逻辑集成在这个方法中
* resHttpHeaders 是否返回http reponse headers, 如果请求参数不为空,会出现 {"_HTTP_HEADERS":[{"key":"value"}]}返回部分
*
* @return
* @throws HttpCallerException
*/
private static HttpReturn doPost(HttpParameters hp, Map extSignHeadersMap) throws HttpCallerException {
if (!hp.getHeaderParamsMap().containsKey(CsbSDKConstants.TRACEID_KEY)) {
hp.getHeaderParamsMap().put(TraceData.TRACEID_KEY, TraceIdUtils.generate());
hp.getHeaderParamsMap().put(TraceData.RPCID_KEY, TraceData.RPCID_DEFAULT);
}
final String requestURL = hp.getRequestUrl();
String apiName = hp.getApi();
String version = hp.getVersion();
Map> paramsMap = hp.getParamsMap();
ContentBody cb = hp.getContentBody();
String accessKey = hp.getAccessKey();
String secretKey = hp.getSecretkey();
String signAlgothrim = hp.getSignAlgorithm();
Map directHeaderParamsMap = hp.getHeaderParamsMap();
String restfulProtocolVersion = hp.getRestfulProtocolVersion();
boolean nonceFlag = hp.isNonce();
HttpReturn ret = new HttpReturn();
ret.diagnosticFlag = hp.isDiagnostic();
long startT = System.currentTimeMillis();
DiagnosticHelper.setStartTime(ret, startT);
HttpClientHelper.validateParams(apiName, accessKey, secretKey, paramsMap);
String charset = hp.getContentType() == null || hp.getContentType().getCharset() == null ? null : hp.getContentType().getCharset().name();
Map> urlParamsMap = HttpClientHelper.parseUrlParamsMap(requestURL, charset, true);
String newRequestURL = HttpClientHelper.generateAsEncodeRequestUrl(requestURL, charset, urlParamsMap);
HttpClientHelper.mergeParamsList(urlParamsMap, paramsMap);
startProcessRestful(newRequestURL, restfulProtocolVersion, urlParamsMap);
if (cb != null && hp.isSignContentBody()) { //判断body是否参与签名
// urlParamsMap.put(ContentBody.CONTENT_BODY_SIGN_KEY, Arrays.asList(cb.getBytesContentBody()));
}
StringBuilder signDiagnosticInfo = DiagnosticHelper.getSignDiagnosticInfo(ret);
Map headerParamsMap = HttpClientHelper.newParamsMap(urlParamsMap, apiName, version, accessKey,
secretKey, true, nonceFlag, extSignHeadersMap, signDiagnosticInfo, hp.getSignImpl(), hp.getVerifySignImpl(), signAlgothrim);
DiagnosticHelper.setSignDiagnosticInfo(ret, signDiagnosticInfo);
endProcessRestful(restfulProtocolVersion, urlParamsMap, headerParamsMap);
if (isCurlResponse()) {
return new HttpReturn(HttpClientHelper.createPostCurlString(newRequestURL, paramsMap, headerParamsMap, cb, directHeaderParamsMap));
}
if (isToHttpRequest()) { //根据请求消息,生成http请求内容。目前使用在控制台发送测试服务消息,通过命令通道转发
String body;
if (cb == null || cb.getStrContentBody() == null) {
body = HttpClientHelper.getParamsUrlEncodingStr(paramsMap);
} else {
body = cb.getStrContentBody();
}
return new HttpReturn(newRequestURL, directHeaderParamsMap, headerParamsMap, body);
}
DiagnosticHelper.calcRequestSize(ret, newRequestURL, paramsMap, cb);
HttpPost httpPost = HttpClientHelper.createPost(newRequestURL, paramsMap, headerParamsMap, cb, hp.getAttachFileMap(), hp.getContentEncoding(), hp.getContentType());
DiagnosticHelper.setRequestHeaders(ret, httpPost.getAllHeaders());
HttpClientHelper.setDirectHeaders(httpPost, directHeaderParamsMap);
httpPost.setConfig(getRequestConfig());
if (SdkLogger.isLoggable()) {
SdkLogger.print("-- prepare time = " + (System.currentTimeMillis() - startT) + " ms ");
}
String msg = null;
try {
ret = doHttpReq(newRequestURL, httpPost, ret);
DiagnosticHelper.setEndTime(ret, System.currentTimeMillis());
DiagnosticHelper.setInvokeTime(ret, System.currentTimeMillis() - startT);
return ret;
} catch (HttpCallerException e) {
msg = e.getMessage();
throw e;
} finally {
log(hp, startT, requestURL, ret, msg);
if (SdkLogger.isLoggable()) {
SdkLogger.print("-- total = " + (System.currentTimeMillis() - startT) + " ms ");
}
}
}
private static HttpReturn doHttpReq(String requestURL, HttpRequestBase httpRequestBase, final HttpReturn ret) throws HttpCallerException {
boolean async = isAsync();
if (async) {
return doAsyncHttpReq(requestURL, httpRequestBase, ret);
} else {
return doSyncHttpReq(requestURL, httpRequestBase, ret);
}
}
private static HttpReturn doSyncHttpReq(String requestURL, HttpRequestBase httpRequestBase, final HttpReturn ret) throws HttpCallerException {
if (SdkLogger.isLoggable()) {
SdkLogger.print("doSyncHttpReq ");
}
HttpReturn rret = ret;
if (ret == null) {
rret = new HttpReturn();
}
long startT = System.currentTimeMillis();
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = null;
if (HttpClientConnManager.HTTP_CLIENT != null) {
httpClient = HttpClientConnManager.HTTP_CLIENT;
} else {
httpClient = createSyncHttpClient(requestURL);
}
if (SdkLogger.isLoggable()) {
SdkLogger.print("--+++ get httpclient costs = " + (System.currentTimeMillis() - startT) + " ms ");
startT = System.currentTimeMillis();
}
try {
try {
response = httpClient.execute(httpRequestBase);
rret.httpCode = response.getStatusLine().getStatusCode();
rret.responseHttpStatus = response.getStatusLine().toString();
rret.responseHeaders = HttpClientHelper.fetchResHeaders(response);
rret.respHttpHeaderMap = HttpClientHelper.fetchResHeaderMap(response);
fetchResponseBody(response, rret);
return rret;
} finally {
if (response != null) {
response.close();
}
//don't close the client for reusing
if (HttpClientConnManager.HTTP_CLIENT == null) {
httpClient.close();
}
if (SdkLogger.isLoggable()) {
SdkLogger.print("-- http req & resp time = " + (System.currentTimeMillis() - startT) + " ms ");
}
}
} catch (Exception e) {
throw new HttpCallerException(e);
}
}
private static HttpReturn doAsyncHttpReq(String requestURL, HttpRequestBase httpRequestBase, final HttpReturn ret) throws HttpCallerException {
if (SdkLogger.isLoggable()) {
SdkLogger.print("doAsyncHttpReq ");
}
HttpReturn rret = ret;
if (ret == null) {
rret = new HttpReturn();
}
long startT = System.currentTimeMillis();
HttpResponse response = null;
CloseableHttpAsyncClient httpClient = createAsyncHttpClient(requestURL);
if (SdkLogger.isLoggable()) {
SdkLogger.print("--+++ get httpclient costs = " + (System.currentTimeMillis() - startT) + " ms ");
startT = System.currentTimeMillis();
}
try {
try {
httpClient.start();
Future asyncFuture = httpClient.execute(httpRequestBase, null);
long waitTime = getFutureGetTimeOut();
if (SdkLogger.isLoggable()) {
SdkLogger.print("future waitTime :" + waitTime);
}
if (waitTime > 0) {
response = asyncFuture.get(waitTime, TimeUnit.MILLISECONDS);
} else {
response = asyncFuture.get();
}
rret.httpCode = response.getStatusLine().getStatusCode();
rret.responseHttpStatus = response.getStatusLine().toString();
rret.responseHeaders = HttpClientHelper.fetchResHeaders(response);
rret.respHttpHeaderMap = HttpClientHelper.fetchResHeaderMap(response);
fetchResponseBody(response, rret);
return rret;
} finally {
httpClient.close();
if (SdkLogger.isLoggable()) {
SdkLogger.print("-- http req & resp time = " + (System.currentTimeMillis() - startT) + " ms ");
}
}
} catch (Exception e) {
throw new HttpCallerException(e);
}
}
static private void fetchResponseBody(HttpResponse response, HttpReturn rret) throws IOException {
HttpEntity responseEntity = response.getEntity();
Header header = responseEntity.getContentType();
if (header == null) {
rret.responseBytes = EntityUtils.toByteArray(responseEntity);
rret.response = new String(rret.responseBytes, HTTP.UTF_8);//兼容csb历史版本的不规范
return;
}
String contentType = header.getValue();
if (contentType == null || contentType.equals("")) {
rret.responseBytes = EntityUtils.toByteArray(responseEntity);
rret.response = new String(rret.responseBytes, HTTP.UTF_8);//兼容csb历史版本的不规范
return;
}
contentType = contentType.toLowerCase();
if (contentType.startsWith("text") || contentType.contains("json") || contentType.contains("xml")) {
rret.response = EntityUtils.toString(responseEntity);
} else {
rret.responseBytes = EntityUtils.toByteArray(responseEntity);
}
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @param accessKey 访问key
* @param secretKey 安全key
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, String version, Map paramsMap,
String accessKey, String secretKey) throws HttpCallerException {
return doPost(requestURL, apiName, version, paramsMap, accessKey, secretKey, null, null);
}
/**
* 使用POST方式调用HTTP服务
*
* @param requestURL 请求的服务URL, 如:http://abc.com:8086/CSB
* @param apiName API名字(服务名)
* @param version API版本号
* @param paramsMap 请求参数key-value参数列表,注:可以将JSON对象转换为String作为参数值
* @param accessKey 访问key
* @param secretKey 安全key
* @param signImpl 签名算法实现类名
* @param verifySignImpl 验签算法实现类名
* @return 调用的返回值,按约定进行解析 (如 JOSN串转换成对象)
* @throws HttpCallerException 调用过程中发生的任何异常
* @deprecated 推荐使用invoke()方法,并使用HttpParameters构造相关的参数
*/
public static String doPost(String requestURL, String apiName, String version, Map paramsMap,
String accessKey, String secretKey, String signImpl, String verifySignImpl) throws HttpCallerException {
HttpParameters hp = HttpParameters.newBuilder().requestURL(requestURL).api(apiName).version(version).putParamsMapAll(paramsMap)
.accessKey(accessKey).secretKey(secretKey).signImpl(signImpl).verifySignImpl(verifySignImpl)
.build();
return doPost(hp, null).getResponseStr();
}
/**
* @param respHttpHeaderMap 当不为空时,会把所有http响应头放入此map
*/
public static String invoke(HttpParameters hp, Map respHttpHeaderMap) throws HttpCallerException {
HttpReturn res = invokeReturn(hp);
if (respHttpHeaderMap != null) {
respHttpHeaderMap.putAll(res.respHttpHeaderMap);
}
return res.getResponseStr();
}
/**
* 使用invoke的方式进行http-api调用
*
* @param hp 各种请求参数的集合类
* @param resHttpHeaders 当该传入参数不为空时,获取http response headers, {"key1":"value1","key2":"value2",...}
* @return
* @throws HttpCallerException
*/
public static String invoke(HttpParameters hp, StringBuffer resHttpHeaders) throws HttpCallerException {
HttpReturn res = invokeReturn(hp);
if (resHttpHeaders != null && res.responseHeaders != null) {
resHttpHeaders.setLength(0);
resHttpHeaders.append(res.responseHeaders);
}
return res.getResponseStr();
}
/**
* 新方法,支持复杂的返回对象(包括诊断信息)
*
* @param hp
* @return
* @throws HttpCallerException
*/
public static HttpReturn invokeReturn(HttpParameters hp) throws HttpCallerException {
if (hp == null)
throw new IllegalArgumentException("null parameter!");
HttpClientHelper.printDebugInfo("-- httpParameters=" + hp.toString());
hp.validate();
Map extSignHeaders = new HashMap();
if ("POST".equalsIgnoreCase(hp.getMethod()) ||
"CPOST".equalsIgnoreCase(hp.getMethod())) {
return doPost(hp, extSignHeaders);
} else
return doGet(hp, extSignHeaders);
}
/**
* 使用invoke的方式进行http-api调用
*
* @param hp 各种请求参数的集合类
* @return
* @throws HttpCallerException
*/
public static String invoke(HttpParameters hp) throws HttpCallerException {
return invoke(hp, (StringBuffer) null);
}
/**
* 一个便利方法,读取一个文件并把其内容转换为 byte[]
*
* @param file 文件的全路径, 最大支持的上传文件的尺寸为10M
* @return
* @throws HttpCallerException
*/
//TODO: remove this unrelated method out of the class
public static byte[] readFileAsByteArray(String file) throws HttpCallerException {
return readFile(new File(file));
}
public static byte[] readFile(File file) {
if (file.exists() && file.isFile() && file.canRead()) {
try {
return readInputStream(new FileInputStream(file));
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
throw new IllegalArgumentException("bad file to read:" + file);
}
}
public static byte[] readInputStream(InputStream inputStream) {
if (inputStream != null) {
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = inputStream.read(b)) != -1) {
bos.write(b, 0, n);
}
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (inputStream != null)
inputStream.close();
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
throw new IllegalArgumentException("inputSteam must no null");
}
}
/**
* 把二进制数据恢复成文件
*
* @param body
* @param filePath
* @param fileName
* @throws HttpCallerException
*/
//TODO: remove this unrelated method out of the class
public static void recoveryFileFromBytes(byte[] body, String filePath, String fileName) throws HttpCallerException {
try {
String fileFullPath = filePath;
if (fileFullPath.endsWith("/")) {
fileFullPath += fileName;
} else {
fileFullPath = fileFullPath + "/" + fileName;
}
File f = new File(fileFullPath);
FileOutputStream out = new FileOutputStream(f);
try {
out.write(body, 0, body.length);
out.flush();
} finally {
if (out != null)
out.close();
}
} catch (Exception e) {
throw new HttpCallerException(e);
}
}
/**
* 判断是否使用NIO,由系统变量http.caller.connection.async设置,默认不用
*
* @return
*/
public static boolean isAsync() {
boolean async = false;
String asyncConf = System.getProperty("http.caller.connection.async");
if (asyncConf != null && asyncConf.length() > 0) {
async = Boolean.valueOf(asyncConf);
}
return async;
}
/**
* 设置nio等待结果的时间,默认为3个等待时间总和外加0.1倍时间,0永不超时
*
* @return
*/
public static long getFutureGetTimeOut() {
RequestConfig requestConfig = getRequestConfig();
long waitTime = 0;
int socketTimeOUt = requestConfig.getSocketTimeout();
if (socketTimeOUt > 0) {
waitTime = waitTime + socketTimeOUt;
}
int crTimeOut = requestConfig.getConnectionRequestTimeout();
if (crTimeOut > 0) {
waitTime = waitTime + crTimeOut;
}
int connTimeOut = requestConfig.getConnectTimeout();
if (connTimeOut > 0) {
waitTime = waitTime + connTimeOut;
}
return (long) (waitTime * 1.1);
}
private static void log(HttpParameters hp, long startTime, String requestUrl, HttpReturn httpReturn, String msg) {
long endTime = System.currentTimeMillis();
Map headers = hp.getHeaderParamsMap();
try {
int qidx = requestUrl.indexOf("?");
String url = qidx > -1 ? requestUrl.substring(0, qidx) : requestUrl;
int cidx = url.indexOf(":");
int pidx = url.indexOf(":", cidx + 3);
if (pidx < 0) {
pidx = url.indexOf("/", cidx + 3);
}
String dest = url.substring(cidx + 3, pidx);
LogUtils.info("{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}", new Object[]{startTime, endTime, endTime - startTime
, "HTTP", IPUtils.getLocalHostIP(), dest
, headers.get(HttpCaller.bizIdKey()), headers.get(CsbSDKConstants.REQUESTID_KEY)
, headers.get(CsbSDKConstants.TRACEID_KEY), headers.get(CsbSDKConstants.RPCID_KEY)
, hp.getApi(), hp.getVersion()
, defaultValue(hp.getAccessKey()), hp.getMethod()
, url, httpReturn.httpCode, httpReturn.responseHttpStatus, defaultValue(msg)});
} catch (Throwable e) {
LogUtils.exception(MessageFormat.format("csb invoke error, api:{0}, version:{1}", hp.getApi(), hp.getVersion()), e);
}
}
private static String defaultValue(String val) {
return val == null ? "" : val.trim();
}
public static void main(String[] args) {
String s = "http://100.100.80.76/api/admin/ServiceRepositoryAPI";
log(HttpParameters.newBuilder().build(), System.currentTimeMillis(), s, null, "ss");
}
}