智能仲裁后端服务

EsignHttpCfgHelper.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. * the License. You may obtain a copy of the License at
  5. *
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. * specific language governing permissions and limitations under the License.
  11. */
  12. package com.ruoyi.common.constant;
  13. import com.ruoyi.common.core.domain.entity.EsignHttpResponse;
  14. import com.ruoyi.common.enums.EsignRequestType;
  15. import com.ruoyi.common.exception.EsignDemoException;
  16. import org.apache.http.*;
  17. import org.apache.http.auth.AuthScope;
  18. import org.apache.http.auth.UsernamePasswordCredentials;
  19. import org.apache.http.client.ClientProtocolException;
  20. import org.apache.http.client.CredentialsProvider;
  21. import org.apache.http.client.HttpRequestRetryHandler;
  22. import org.apache.http.client.config.RequestConfig;
  23. import org.apache.http.client.entity.UrlEncodedFormEntity;
  24. import org.apache.http.client.methods.CloseableHttpResponse;
  25. import org.apache.http.client.methods.HttpRequestBase;
  26. import org.apache.http.client.protocol.HttpClientContext;
  27. import org.apache.http.client.utils.URIBuilder;
  28. import org.apache.http.config.Registry;
  29. import org.apache.http.config.RegistryBuilder;
  30. import org.apache.http.conn.ConnectTimeoutException;
  31. import org.apache.http.conn.socket.ConnectionSocketFactory;
  32. import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
  33. import org.apache.http.conn.socket.PlainConnectionSocketFactory;
  34. import org.apache.http.conn.ssl.NoopHostnameVerifier;
  35. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  36. import org.apache.http.entity.ByteArrayEntity;
  37. import org.apache.http.entity.ContentType;
  38. import org.apache.http.entity.StringEntity;
  39. import org.apache.http.impl.client.BasicCredentialsProvider;
  40. import org.apache.http.impl.client.CloseableHttpClient;
  41. import org.apache.http.impl.client.HttpClientBuilder;
  42. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  43. import org.apache.http.message.BasicNameValuePair;
  44. import org.apache.http.protocol.HttpContext;
  45. import org.apache.http.util.EntityUtils;
  46. import org.slf4j.Logger;
  47. import org.slf4j.LoggerFactory;
  48. import javax.net.ssl.*;
  49. import java.io.IOException;
  50. import java.io.InterruptedIOException;
  51. import java.net.UnknownHostException;
  52. import java.security.cert.CertificateException;
  53. import java.security.cert.X509Certificate;
  54. import java.text.MessageFormat;
  55. import java.util.ArrayList;
  56. import java.util.Arrays;
  57. import java.util.List;
  58. import java.util.Map;
  59. /**
  60. * @description Http请求 辅助类
  61. * @author 澄泓
  62. * @since JDK1.7
  63. */
  64. public class EsignHttpCfgHelper {
  65. private static Logger LOGGER = LoggerFactory.getLogger(EsignHttpCfgHelper.class);
  66. /**
  67. * 超时时间,默认15000毫秒
  68. */
  69. private static int MAX_TIMEOUT = 15000;
  70. /**
  71. * 请求池最大连接数,默认100个
  72. */
  73. private static int MAX_TOTAL=100;
  74. /**
  75. * 单域名最大的连接数,默认50个
  76. */
  77. private static int ROUTE_MAX_TOTAL=50;
  78. /**
  79. * 请求失败重试次数,默认3次
  80. */
  81. private static int MAX_RETRY = 3;
  82. /**
  83. * 是否需要域名校验,默认不需要校验
  84. */
  85. private static boolean SSL_VERIFY=false;
  86. /**
  87. * 正向代理IP
  88. */
  89. private static String PROXY_IP;
  90. /**
  91. * 正向代理端口,默认8888
  92. */
  93. private static int PROXY_PORT=8888;
  94. /**
  95. * 代理协议,默认http
  96. */
  97. private static String PROXY_AGREEMENT="http";
  98. /**
  99. * 是否开启代理,默认false
  100. */
  101. private static boolean OPEN_PROXY=false;
  102. /**
  103. * 代理服务器用户名
  104. */
  105. private static String PROXY_USERNAME="";
  106. /**
  107. * 代理服务器密码
  108. */
  109. private static String PROXY_PASSWORD="";
  110. private static PoolingHttpClientConnectionManager connMgr; //连接池
  111. private static HttpRequestRetryHandler retryHandler; //重试机制
  112. private static CloseableHttpClient httpClient=null;
  113. public static int getMaxTimeout() {
  114. return MAX_TIMEOUT;
  115. }
  116. public static void setMaxTimeout(int maxTimeout) {
  117. MAX_TIMEOUT = maxTimeout;
  118. }
  119. public static int getMaxTotal() {
  120. return MAX_TOTAL;
  121. }
  122. public static void setMaxTotal(int maxTotal) {
  123. MAX_TOTAL = maxTotal;
  124. }
  125. public static int getRouteMaxTotal() {
  126. return ROUTE_MAX_TOTAL;
  127. }
  128. public static void setRouteMaxTotal(int routeMaxTotal) {
  129. ROUTE_MAX_TOTAL = routeMaxTotal;
  130. }
  131. public static int getMaxRetry() {
  132. return MAX_RETRY;
  133. }
  134. public static void setMaxRetry(int maxRetry) {
  135. MAX_RETRY = maxRetry;
  136. }
  137. public static boolean isSslVerify() {
  138. return SSL_VERIFY;
  139. }
  140. public static void setSslVerify(boolean sslVerify) {
  141. SSL_VERIFY = sslVerify;
  142. }
  143. public static String getProxyIp() {
  144. return PROXY_IP;
  145. }
  146. public static void setProxyIp(String proxyIp) {
  147. PROXY_IP = proxyIp;
  148. }
  149. public static int getProxyPort() {
  150. return PROXY_PORT;
  151. }
  152. public static void setProxyPort(int proxyPort) {
  153. PROXY_PORT = proxyPort;
  154. }
  155. public static String getProxyAgreement() {
  156. return PROXY_AGREEMENT;
  157. }
  158. public static void setProxyAgreement(String proxyAgreement) {
  159. PROXY_AGREEMENT = proxyAgreement;
  160. }
  161. public static boolean getOpenProxy() {
  162. return OPEN_PROXY;
  163. }
  164. public static void setOpenProxy(boolean openProxy) {
  165. OPEN_PROXY = openProxy;
  166. }
  167. public static String getProxyUsername() {
  168. return PROXY_USERNAME;
  169. }
  170. public static void setProxyUserame(String proxyUsername) {
  171. PROXY_USERNAME = proxyUsername;
  172. }
  173. public static String getProxyPassword() {
  174. return PROXY_PASSWORD;
  175. }
  176. public static void setProxyPassword(String proxyPassword) {
  177. PROXY_PASSWORD = proxyPassword;
  178. }
  179. /**
  180. * 不允许外部创建实例
  181. */
  182. private EsignHttpCfgHelper() {
  183. }
  184. //------------------------------公有方法start--------------------------------------------
  185. /**
  186. * @description 发起HTTP / HTTPS 请求
  187. *
  188. * @param reqType
  189. * {@link EsignRequestType} 请求类型 GET、 POST 、 DELETE 、 PUT
  190. * @param httpUrl
  191. * {@link String} 请求目标地址
  192. * @param headers
  193. * {@link Map} 请求头
  194. * @param param
  195. * {@link Object} 参数
  196. * @return
  197. * @throws EsignDemoException
  198. * @author 澄泓
  199. */
  200. public static EsignHttpResponse sendHttp(EsignRequestType reqType, String httpUrl, Map<String, String> headers, Object param, boolean debug)
  201. throws EsignDemoException {
  202. HttpRequestBase reqBase=null;
  203. if(httpUrl.startsWith("http")){
  204. reqBase=reqType.getHttpType(httpUrl);
  205. }else{
  206. throw new EsignDemoException("请求url地址格式错误");
  207. }
  208. if(debug){
  209. LOGGER.info("请求头:{}",headers+"\n");
  210. LOGGER.info("请求参数\n{}", param+"\n");
  211. LOGGER.info("请求地址\n:{}\n请求方式\n:{}",reqBase.getURI(),reqType+"\n");
  212. }
  213. //请求方法不是GET或者DELETE时传入body体,否则不传入。
  214. String[] methods = {"DELETE", "GET"};
  215. if(param instanceof String&&Arrays.binarySearch(methods, reqType.name())<0){//POST或者PUT请求
  216. ((HttpEntityEnclosingRequest) reqBase).setEntity(
  217. new StringEntity(String.valueOf(param), ContentType.create("application/json", "UTF-8")));
  218. }
  219. //参数时字节流数组
  220. else if(param instanceof byte[]) {
  221. reqBase=reqType.getHttpType(httpUrl);
  222. byte[] paramBytes = (byte[])param;
  223. ((HttpEntityEnclosingRequest) reqBase).setEntity(new ByteArrayEntity(paramBytes));
  224. }
  225. //参数是form表单时
  226. else if(param instanceof List){
  227. ((HttpEntityEnclosingRequest) reqBase).setEntity(new UrlEncodedFormEntity((Iterable<? extends NameValuePair>) param));
  228. }
  229. httpClient = getHttpClient();
  230. config(reqBase);
  231. //设置请求头
  232. if(headers != null &&headers.size()>0) {
  233. for(Map.Entry<String, String> entry :headers.entrySet()) {
  234. reqBase.setHeader(entry.getKey(), entry.getValue());
  235. }
  236. }
  237. //响应对象
  238. CloseableHttpResponse res = null;
  239. //响应内容
  240. String resCtx = null;
  241. int status;
  242. EsignHttpResponse esignHttpResponse = new EsignHttpResponse();
  243. try {
  244. //执行请求
  245. res = httpClient.execute(reqBase);
  246. status=res.getStatusLine().getStatusCode();
  247. //获取请求响应对象和响应entity
  248. HttpEntity httpEntity = res.getEntity();
  249. if(httpEntity != null) {
  250. resCtx = EntityUtils.toString(httpEntity,"utf-8");
  251. }
  252. if(debug) {
  253. LOGGER.info("响应\n{}", resCtx + "\n");
  254. LOGGER.info("----------------------------end------------------------");
  255. }
  256. } catch (NoHttpResponseException e) {
  257. throw new EsignDemoException("服务器丢失了",e);
  258. } catch (SSLHandshakeException e){
  259. String msg = MessageFormat.format("SSL握手异常", e);
  260. EsignDemoException ex = new EsignDemoException(msg, e);
  261. throw ex;
  262. } catch (UnknownHostException e){
  263. EsignDemoException ex = new EsignDemoException("服务器找不到", e);
  264. ex.initCause(e);
  265. throw ex;
  266. } catch(ConnectTimeoutException e){
  267. EsignDemoException ex = new EsignDemoException("连接超时", e);
  268. ex.initCause(e);
  269. throw ex;
  270. } catch(SSLException e){
  271. EsignDemoException ex = new EsignDemoException("SSL异常",e);
  272. ex.initCause(e);
  273. throw ex;
  274. } catch (ClientProtocolException e) {
  275. EsignDemoException ex = new EsignDemoException("请求头异常",e);
  276. ex.initCause(e);
  277. throw ex;
  278. } catch (IOException e) {
  279. EsignDemoException ex = new EsignDemoException("网络请求失败",e);
  280. ex.initCause(e);
  281. throw ex;
  282. } finally {
  283. if(res != null) {
  284. try {
  285. res.close();
  286. } catch (IOException e) {
  287. EsignDemoException ex = new EsignDemoException("--->>关闭请求响应失败",e);
  288. ex.initCause(e);
  289. throw ex;
  290. }
  291. }
  292. }
  293. esignHttpResponse.setStatus(status);
  294. esignHttpResponse.setBody(resCtx);
  295. return esignHttpResponse;
  296. }
  297. //------------------------------公有方法end----------------------------------------------
  298. //------------------------------私有方法start--------------------------------------------
  299. /**
  300. * @description 请求头和超时时间配置
  301. *
  302. * @param httpReqBase
  303. * @author 澄泓
  304. */
  305. private static void config(HttpRequestBase httpReqBase) {
  306. // 配置请求的超时设置
  307. RequestConfig.Builder builder = RequestConfig.custom()
  308. .setConnectionRequestTimeout(MAX_TIMEOUT)
  309. .setConnectTimeout(MAX_TIMEOUT)
  310. .setSocketTimeout(MAX_TIMEOUT);
  311. if(OPEN_PROXY){
  312. HttpHost proxy=new HttpHost(PROXY_IP,PROXY_PORT,PROXY_AGREEMENT);
  313. builder.setProxy(proxy);
  314. }
  315. RequestConfig requestConfig = builder.build();
  316. httpReqBase.setConfig(requestConfig);
  317. }
  318. /**
  319. * @description 连接池配置
  320. *
  321. * @return
  322. * @author 澄泓
  323. */
  324. private static void cfgPoolMgr() throws EsignDemoException {
  325. ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
  326. LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
  327. if(!SSL_VERIFY){
  328. sslsf=sslConnectionSocketFactory();
  329. }
  330. Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
  331. .register("http", plainsf)
  332. .register("https", sslsf)
  333. .build();
  334. //连接池管理器
  335. connMgr = new PoolingHttpClientConnectionManager(registry);
  336. //请求池最大连接数
  337. connMgr.setMaxTotal(MAX_TOTAL);
  338. //但域名最大的连接数
  339. connMgr.setDefaultMaxPerRoute(ROUTE_MAX_TOTAL);
  340. }
  341. /**
  342. * @description 设置重试机制
  343. *
  344. * @author 澄泓
  345. */
  346. private static void cfgRetryHandler() {
  347. retryHandler = new HttpRequestRetryHandler() {
  348. @Override
  349. public boolean retryRequest(IOException e, int excCount, HttpContext ctx) {
  350. //超过最大重试次数,就放弃
  351. if(excCount > MAX_RETRY) {
  352. return false;
  353. }
  354. //服务器丢掉了链接,就重试
  355. if(e instanceof NoHttpResponseException) {
  356. return true;
  357. }
  358. //不重试SSL握手异常
  359. if(e instanceof SSLHandshakeException) {
  360. return false;
  361. }
  362. //中断
  363. if(e instanceof InterruptedIOException) {
  364. return false;
  365. }
  366. //目标服务器不可达
  367. if(e instanceof UnknownHostException) {
  368. return false;
  369. }
  370. //连接超时
  371. //SSL异常
  372. if(e instanceof SSLException) {
  373. return false;
  374. }
  375. HttpClientContext clientCtx = HttpClientContext.adapt(ctx);
  376. HttpRequest req = clientCtx.getRequest();
  377. //如果是幂等请求,就再次尝试
  378. if(!(req instanceof HttpEntityEnclosingRequest)) {
  379. return true;
  380. }
  381. return false;
  382. }
  383. };
  384. }
  385. /**
  386. * 忽略域名校验
  387. */
  388. private static SSLConnectionSocketFactory sslConnectionSocketFactory() throws EsignDemoException {
  389. try {
  390. SSLContext ctx = SSLContext.getInstance("TLS"); // 创建一个上下文(此处指定的协议类型似乎不是重点)
  391. X509TrustManager tm = new X509TrustManager() { // 创建一个跳过SSL证书的策略
  392. public X509Certificate[] getAcceptedIssuers() {
  393. return null;
  394. }
  395. public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
  396. }
  397. public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
  398. }
  399. };
  400. ctx.init(null, new TrustManager[] { tm }, null); // 使用上面的策略初始化上下文
  401. return new SSLConnectionSocketFactory(ctx, new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }, null, NoopHostnameVerifier.INSTANCE);
  402. }catch (Exception e){
  403. EsignDemoException ex = new EsignDemoException("忽略域名校验失败",e);
  404. ex.initCause(e);
  405. throw ex;
  406. }
  407. }
  408. /**
  409. * @description 获取单例HttpClient
  410. *
  411. * @return
  412. * @author 澄泓
  413. */
  414. private static synchronized CloseableHttpClient getHttpClient() throws EsignDemoException {
  415. if(httpClient==null) {
  416. CredentialsProvider credsProvider = new BasicCredentialsProvider();
  417. credsProvider.setCredentials(new AuthScope(PROXY_IP,PROXY_PORT),new UsernamePasswordCredentials(PROXY_USERNAME, PROXY_PASSWORD));
  418. cfgPoolMgr();
  419. cfgRetryHandler();
  420. HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
  421. httpClient = httpClientBuilder.setDefaultCredentialsProvider(credsProvider).setConnectionManager(connMgr).setRetryHandler(retryHandler).build();
  422. }
  423. return httpClient;
  424. }
  425. //------------------------------私有方法end----------------------------------------------
  426. }