RestApiUtils.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. package com.yiidata.intergration.api.utils;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.datasophon.api.utils.HttpUtils;
  6. import com.google.common.io.ByteStreams;
  7. import com.google.common.net.HttpHeaders;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.apache.commons.lang.StringUtils;
  10. import org.apache.http.Header;
  11. import org.apache.http.HeaderElement;
  12. import org.apache.http.HttpEntity;
  13. import org.apache.http.HttpResponse;
  14. import org.apache.http.NameValuePair;
  15. import org.apache.http.client.HttpClient;
  16. import org.apache.http.client.config.RequestConfig;
  17. import org.apache.http.client.methods.CloseableHttpResponse;
  18. import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
  19. import org.apache.http.client.methods.HttpGet;
  20. import org.apache.http.client.methods.HttpPost;
  21. import org.apache.http.client.methods.HttpPut;
  22. import org.apache.http.client.methods.HttpUriRequest;
  23. import org.apache.http.config.Registry;
  24. import org.apache.http.config.RegistryBuilder;
  25. import org.apache.http.config.SocketConfig;
  26. import org.apache.http.conn.socket.ConnectionSocketFactory;
  27. import org.apache.http.conn.socket.PlainConnectionSocketFactory;
  28. import org.apache.http.conn.ssl.DefaultHostnameVerifier;
  29. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  30. import org.apache.http.entity.FileEntity;
  31. import org.apache.http.entity.StringEntity;
  32. import org.apache.http.entity.mime.MultipartEntityBuilder;
  33. import org.apache.http.impl.client.BasicCookieStore;
  34. import org.apache.http.impl.client.CloseableHttpClient;
  35. import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
  36. import org.apache.http.impl.client.DefaultRedirectStrategy;
  37. import org.apache.http.impl.client.HttpClients;
  38. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  39. import org.apache.http.params.BasicHttpParams;
  40. import org.apache.http.util.EntityUtils;
  41. import org.slf4j.Logger;
  42. import org.slf4j.LoggerFactory;
  43. import javax.net.ssl.SSLContext;
  44. import javax.net.ssl.TrustManager;
  45. import javax.net.ssl.X509TrustManager;
  46. import java.io.File;
  47. import java.io.FileNotFoundException;
  48. import java.io.FileOutputStream;
  49. import java.io.IOException;
  50. import java.io.InputStream;
  51. import java.io.OutputStream;
  52. import java.net.URLDecoder;
  53. import java.nio.charset.StandardCharsets;
  54. import java.nio.file.Paths;
  55. import java.security.KeyManagementException;
  56. import java.security.NoSuchAlgorithmException;
  57. import java.security.cert.CertificateException;
  58. import java.util.HashMap;
  59. import java.util.Map;
  60. import java.util.Objects;
  61. import java.util.Optional;
  62. import java.util.concurrent.TimeUnit;
  63. import java.util.function.Consumer;
  64. /**
  65. *
  66. * 封装 RestApi 调用
  67. *
  68. * <pre>
  69. *
  70. * Created by zhaopx.
  71. * User: zhaopx
  72. * Date: 2020/4/3
  73. * Time: 17:38
  74. *
  75. * </pre>
  76. *
  77. * @author zhaopx
  78. */
  79. public class RestApiUtils {
  80. static Logger log = LoggerFactory.getLogger(RestApiUtils.class);
  81. /**
  82. * http client
  83. */
  84. static final CloseableHttpClient httpClient;
  85. /**
  86. * Cookie store
  87. */
  88. private final static BasicCookieStore cookieStore = new BasicCookieStore();
  89. static {
  90. try {
  91. //1. 设置协议http和https对应的处理socket链接工厂的对象
  92. Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
  93. .register("http", PlainConnectionSocketFactory.INSTANCE)
  94. .register("https", new SSLConnectionSocketFactory(createIgnoreVerifySSL(), null, null, new DefaultHostnameVerifier()))
  95. .build();
  96. //2. Socket层优化
  97. SocketConfig socketConfig = SocketConfig.custom()
  98. .setTcpNoDelay(true) // 禁用Nagle算法
  99. .setSoKeepAlive(true) // 启用TCP KeepAlive
  100. .setSoReuseAddress(true)
  101. .build();
  102. PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
  103. // 连接池大小
  104. cm.setMaxTotal(220);
  105. cm.setDefaultMaxPerRoute((int)(cm.getMaxTotal() * 0.8));
  106. cm.setDefaultSocketConfig(socketConfig);
  107. httpClient = HttpClients.custom()
  108. .setConnectionManager(cm)
  109. .setDefaultCookieStore(cookieStore)
  110. .setDefaultRequestConfig(RequestConfig.custom()
  111. .setConnectTimeout(65000)
  112. .setSocketTimeout(30000)
  113. .setConnectionRequestTimeout(30000).build())
  114. .setRedirectStrategy(new DefaultRedirectStrategy() {
  115. @Override
  116. protected boolean isRedirectable(String method) {
  117. // If the connection target is FE, you need to handle 307 redirect.
  118. return true;
  119. }
  120. })
  121. .setRetryHandler(new DefaultHttpRequestRetryHandler(3, false))
  122. .setConnectionManagerShared(false) // 共享连接池
  123. .evictIdleConnections(15, TimeUnit.SECONDS) // 定期清理空闲连接
  124. .build();
  125. } catch (Exception e) {
  126. throw new IllegalStateException(e);
  127. }
  128. }
  129. /**
  130. * 绕过验证
  131. *
  132. * @return
  133. * @throws NoSuchAlgorithmException
  134. * @throws KeyManagementException
  135. */
  136. public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
  137. SSLContext sc = SSLContext.getInstance("TLSv1.2");
  138. // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
  139. X509TrustManager trustManager = new X509TrustManager() {
  140. @Override
  141. public void checkClientTrusted(
  142. java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
  143. String paramString) throws CertificateException {
  144. }
  145. @Override
  146. public void checkServerTrusted(
  147. java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
  148. String paramString) throws CertificateException {
  149. }
  150. @Override
  151. public java.security.cert.X509Certificate[] getAcceptedIssuers() {
  152. return null;
  153. }
  154. };
  155. sc.init(null, new TrustManager[] { trustManager }, null);
  156. return sc;
  157. }
  158. /**
  159. * 调用一次远程 api
  160. *
  161. * @param url
  162. * @return
  163. * @throws IOException
  164. */
  165. public static Map<String, Object> post(String url) throws IOException {
  166. return post(url, new HashMap<>(), false);
  167. }
  168. /**
  169. * 调用一次远程 api
  170. *
  171. * @param url
  172. * @return
  173. * @throws IOException
  174. */
  175. public static Map<String, Object> post(String url, boolean not200ThrowError) throws IOException {
  176. return post(url, new HashMap<>(), not200ThrowError);
  177. }
  178. /**
  179. * 通过 Post 请求调用Rest 接口
  180. *
  181. * @param url
  182. * @param json
  183. * @return
  184. * @throws IOException
  185. */
  186. public static Map<String, Object> post(String url, Map<String, Object> json) throws IOException {
  187. return post(url, json, false);
  188. }
  189. /**
  190. * 通过 Post 请求调用Rest 接口
  191. *
  192. * @param url
  193. * @param json
  194. * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
  195. * @return
  196. * @throws IOException
  197. */
  198. public static Map<String, Object> post(String url, Map<String, Object> json, boolean not200ThrowError) throws IOException {
  199. return post(url, JSON.toJSONString(json), not200ThrowError);
  200. }
  201. /**
  202. * POST 请求,执行远程
  203. *
  204. * @param url
  205. * @param jsonStr
  206. * @param not200ThrowError
  207. * @return
  208. * @throws IOException
  209. */
  210. public static Map<String, Object> post(String url, String jsonStr, boolean not200ThrowError) throws IOException {
  211. return post(url, jsonStr, new HashMap<>(), not200ThrowError);
  212. }
  213. /**
  214. * POST 请求执行远程链接
  215. *
  216. * @param url
  217. * @param jsonStr 请求 Body 体
  218. * @param header 请求头
  219. * @param not200ThrowError
  220. * @return
  221. * @throws IOException
  222. */
  223. public static Map<String, Object> post(String url, String jsonStr, Map<String, String> header, boolean not200ThrowError) throws IOException {
  224. HttpPost post = new HttpPost(url);
  225. StringEntity entity = new StringEntity(jsonStr, "UTF-8");
  226. entity.setContentType("application/json");
  227. post.setEntity(entity);
  228. if(header != null && !header.isEmpty()) {
  229. for (Map.Entry<String, String> entry : header.entrySet()) {
  230. post.addHeader(entry.getKey(), entry.getValue());
  231. }
  232. }
  233. CloseableHttpResponse resp = null;
  234. try {
  235. resp = httpClient.execute(post);
  236. log.info("execute[post] url {} return code: {}", url, resp.getStatusLine().getStatusCode());
  237. HttpEntity entity1 = resp.getEntity();
  238. String result = EntityUtils.toString(entity1);
  239. EntityUtils.consume(entity1);
  240. if(not200ThrowError && resp.getStatusLine().getStatusCode() != 200) {
  241. throw new IOException(result);
  242. }
  243. Object jsonResult = JSON.parse(result);
  244. JSONObject jsonObject = new JSONObject(2);
  245. if(jsonResult instanceof JSONArray) {
  246. jsonObject.put("result", jsonResult);
  247. } else {
  248. jsonObject = (JSONObject) jsonResult;
  249. }
  250. jsonObject.put("status_code", resp.getStatusLine().getStatusCode());
  251. return jsonObject;
  252. } finally {
  253. if(resp != null) {
  254. resp.close();
  255. }
  256. }
  257. }
  258. /**
  259. * 执行 execute 返回 Map 数据对象
  260. * @param request
  261. * @param not200ThrowError
  262. * @return
  263. * @throws IOException
  264. */
  265. public static Map<String, Object> execute(HttpUriRequest request, boolean not200ThrowError) throws IOException {
  266. CloseableHttpResponse resp = null;
  267. try {
  268. resp = httpClient.execute(request);
  269. log.info("execute[{}] url {} return code: {}", request.getMethod(), request.getURI(), resp.getStatusLine().getStatusCode());
  270. HttpEntity entity1 = resp.getEntity();
  271. String result = EntityUtils.toString(entity1);
  272. EntityUtils.consume(entity1);
  273. if(not200ThrowError && resp.getStatusLine().getStatusCode() != 200) {
  274. throw new IOException(result);
  275. }
  276. Object jsonResult = JSON.parse(result);
  277. JSONObject jsonObject = new JSONObject(2);
  278. if(jsonResult instanceof JSONArray) {
  279. jsonObject.put("result", jsonResult);
  280. } else {
  281. jsonObject = (JSONObject) jsonResult;
  282. }
  283. jsonObject.put("status_code", resp.getStatusLine().getStatusCode());
  284. return jsonObject;
  285. } finally {
  286. if(resp != null) {
  287. resp.close();
  288. }
  289. }
  290. }
  291. /**
  292. * 执行任意 request,并采用回调 consumer
  293. * @param request
  294. * @param consumer
  295. * @throws IOException
  296. */
  297. public static void execute(HttpUriRequest request, Consumer<HttpResponse> consumer) throws IOException {
  298. CloseableHttpResponse resp = null;
  299. try {
  300. resp = httpClient.execute(request);
  301. log.info("execute[{}] url {} return code: {}", request.getMethod(), request.getURI(), resp.getStatusLine().getStatusCode());
  302. consumer.accept(resp);
  303. } finally {
  304. if (resp != null) {
  305. resp.close();
  306. }
  307. }
  308. }
  309. //---------
  310. /**
  311. * 调用一次远程 api
  312. *
  313. * @param url
  314. * @return
  315. * @throws IOException
  316. */
  317. public static Map<String, Object> get(String url) throws IOException {
  318. return get(url, new HashMap<>(), false);
  319. }
  320. /**
  321. * 调用一次远程 api
  322. *
  323. * @param url
  324. * @return
  325. * @throws IOException
  326. */
  327. public static Map<String, Object> get(String url, boolean not200ThrowError) throws IOException {
  328. return get(url, new HashMap<>(), not200ThrowError);
  329. }
  330. /**
  331. * 通过 Post 请求调用Rest 接口
  332. *
  333. * @param url
  334. * @param json
  335. * @return
  336. * @throws IOException
  337. */
  338. public static Map<String, Object> get(String url, Map<String, Object> json) throws IOException {
  339. return get(url, json, false);
  340. }
  341. /**
  342. * 通过 Post 请求调用Rest 接口
  343. *
  344. * @param url
  345. * @param json
  346. * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
  347. * @return
  348. * @throws IOException
  349. */
  350. public static Map<String, Object> get(String url, Map<String, Object> json, boolean not200ThrowError) throws IOException {
  351. return get(url, json, new HashMap<>(), not200ThrowError);
  352. }
  353. /**
  354. * 通过 Post 请求调用Rest 接口
  355. *
  356. * @param url
  357. * @param json
  358. * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
  359. * @return
  360. * @throws IOException
  361. */
  362. public static Map<String, Object> get(String url, Map<String, Object> json, Map<String, String> header, boolean not200ThrowError) throws IOException {
  363. HttpGet get = new HttpGet(url);
  364. if(json != null && !json.isEmpty()) {
  365. BasicHttpParams params = new BasicHttpParams();
  366. for (Map.Entry<String, Object> entry : json.entrySet()) {
  367. params.setParameter(entry.getKey(), entry.getValue());
  368. }
  369. get.setParams(params);
  370. }
  371. if(header != null && !header.isEmpty()) {
  372. for (Map.Entry<String, String> entry : header.entrySet()) {
  373. get.addHeader(entry.getKey(), entry.getValue());
  374. }
  375. }
  376. CloseableHttpResponse resp = null;
  377. try {
  378. resp = httpClient.execute(get);
  379. log.info("execute[get] url {} return code: {}", url, resp.getStatusLine().getStatusCode());
  380. final String contentType = Optional.ofNullable(resp.getFirstHeader("Content-Type")).map(Header::getValue).orElse("text/html");
  381. final HttpEntity entity = resp.getEntity();
  382. String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
  383. EntityUtils.consume(entity);
  384. if(not200ThrowError && resp.getStatusLine().getStatusCode() != 200) {
  385. throw new IOException(result);
  386. }
  387. // 判断一下返回 类型
  388. JSONObject jsonObject = new JSONObject(2);
  389. if(!contentType.contains("json")) {
  390. jsonObject.put("result", result);
  391. } else {
  392. Object jsonResult = JSON.parse(result);
  393. if(jsonResult instanceof JSONArray) {
  394. jsonObject.put("result", jsonResult);
  395. } else {
  396. jsonObject = (JSONObject) jsonResult;
  397. }
  398. }
  399. jsonObject.put("status_code", resp.getStatusLine().getStatusCode());
  400. return jsonObject;
  401. } finally {
  402. if(resp != null) {
  403. resp.close();
  404. }
  405. }
  406. }
  407. /**
  408. * 根据url下载文件,保存到filepath中
  409. *
  410. * @param url
  411. * @param downloadDir
  412. * @return 返回 下载的文件路径
  413. */
  414. public static String download(String url, File downloadDir) throws IOException {
  415. return download(url, new HashMap<>(), downloadDir, new NoProcessCall());
  416. }
  417. /**
  418. * 根据url下载文件,保存到filepath中
  419. *
  420. * @param url
  421. * @param downloadDir
  422. * @return 返回 下载的文件路径
  423. */
  424. public static String download(String url, Map<String, String> headers, File downloadDir) throws IOException {
  425. return download(url, headers, downloadDir, new NoProcessCall());
  426. }
  427. /**
  428. * 根据url下载文件,保存到filepath中
  429. *
  430. * @param url
  431. * @param downloadDir
  432. * @return 返回 下载的文件路径
  433. */
  434. public static String download(String url, Map<String, String> headers, File downloadDir, ProcessCall call) throws IOException {
  435. if(!downloadDir.exists()) {
  436. if(!downloadDir.mkdirs()) {
  437. throw new IOException(downloadDir.getAbsolutePath() + " not exists, do can not mkdir.");
  438. }
  439. }
  440. // 构造 Header,并且绑定,下载时登录,其实只要绑定 SessionID 就可以了
  441. HttpGet httpget = new HttpGet(url);
  442. if(headers != null) {
  443. for (Map.Entry<String, String> entry : headers.entrySet()) {
  444. httpget.setHeader(entry.getKey(), entry.getValue());
  445. }
  446. }
  447. // 开始下载
  448. HttpResponse response = httpClient.execute(httpget);
  449. String fileName = null;
  450. final Header contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
  451. if(StringUtils.contains(contentType.getValue(), "application/octet-stream") ||
  452. StringUtils.contains(contentType.getValue(), "application/force-download")) {
  453. // 下载文件
  454. fileName = getFileName(response);
  455. if(StringUtils.isBlank(fileName)) {
  456. log.warn(response.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION) + " can 'not found filename.");
  457. }
  458. }
  459. if(StringUtils.isBlank(fileName)) {
  460. fileName = getFileName(response);
  461. }
  462. if(StringUtils.isBlank(fileName)) {
  463. //无法从 header中获得文件名,如果路径是 /path/for/bar.zip 以 bar.zip 为文件名
  464. final String rawPath = httpget.getURI().getRawPath();
  465. if(!rawPath.endsWith("/")) {
  466. fileName = Paths.get(rawPath).getFileName().toString();
  467. }
  468. if(StringUtils.isBlank(fileName)) {
  469. log.warn("can not found download filename, use system timestamp.");
  470. fileName = String.valueOf(System.currentTimeMillis());
  471. }
  472. }
  473. log.info("download filename: {}", fileName);
  474. HttpEntity entity = response.getEntity();
  475. File filepath = new File(downloadDir, fileName);
  476. final long fileSize = entity.getContentLength();
  477. call.fileSize(fileSize);
  478. call.process(0.0f);
  479. try(InputStream is = entity.getContent(); FileOutputStream fileout = new FileOutputStream(filepath);) {
  480. byte[] buf = new byte[ 4 * 1024]; //4KB 缓冲区
  481. long total = 0;
  482. while (true) {
  483. int r = is.read(buf);
  484. if (r == -1) {
  485. break;
  486. }
  487. fileout.write(buf, 0, r);
  488. total += r;
  489. if(total % 2048 == 1024) {
  490. // 每 4M 推送一次进度
  491. call.process(fileSize > 0 ? (float) total / fileSize : 0.0f);
  492. }
  493. }
  494. fileout.flush();
  495. }
  496. call.process(1.0f);
  497. return filepath.getAbsolutePath();
  498. }
  499. /**
  500. * 获取response header中Content-Disposition中的filename值
  501. *
  502. * @param response
  503. * @return
  504. */
  505. private static String getFileName(HttpResponse response) {
  506. Header contentHeader = response.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION);
  507. String filename = null;
  508. if (contentHeader != null) {
  509. HeaderElement[] values = contentHeader.getElements();
  510. if (values.length >= 1) {
  511. NameValuePair param = values[0].getParameterByName("filename");
  512. if (param != null) {
  513. try {
  514. if(param.getValue() != null && param.getValue().contains("%")) {
  515. //filename = new String(param.getValue().toString().getBytes(), "utf-8");
  516. filename = URLDecoder.decode(param.getValue(), "UTF-8");
  517. } else {
  518. filename = param.getValue();
  519. }
  520. } catch (Exception e) {
  521. filename = param.getValue();
  522. }
  523. }
  524. }
  525. }
  526. return filename;
  527. }
  528. // -------------------------------上传文件-----------------------------------
  529. /**
  530. * 根据url上传文件
  531. *
  532. * @param url
  533. * @param uploadFile
  534. * @return 返回 下载的文件路径
  535. */
  536. public static Map<String, Object> upload(String url,
  537. File uploadFile) throws IOException {
  538. return upload(url, null, null, uploadFile);
  539. }
  540. /**
  541. * 根据url上传文件
  542. *
  543. * @param url
  544. * @param json payload 负载的消息参数
  545. * @param uploadFile
  546. * @return 返回 下载的文件路径
  547. */
  548. public static Map<String, Object> upload(String url,
  549. Map<String, Object> json,
  550. File uploadFile) throws IOException {
  551. return upload(url, json, null, uploadFile);
  552. }
  553. /**
  554. * 根据url上传文件
  555. *
  556. * @param url
  557. * @param json payload 负载的消息参数
  558. * @param headers Http Header
  559. * @param uploadFile
  560. * @return 返回 下载的文件路径
  561. */
  562. public static Map<String, Object> upload(String url,
  563. Map<String, Object> json,
  564. Map<String, String> headers,
  565. File uploadFile) throws IOException {
  566. return upload(url, json, headers, uploadFile, -1, -1, true);
  567. }
  568. /**
  569. * 根据url上传文件
  570. *
  571. * @param url
  572. * @param json payload 负载的消息参数
  573. * @param headers Http Header
  574. * @param uploadFile
  575. * @param usePut 采用 PUT 请求上传文件
  576. * @return 返回 下载的文件路径
  577. */
  578. public static Map<String, Object> upload(String url,
  579. Map<String, Object> json,
  580. Map<String, String> headers,
  581. File uploadFile,
  582. boolean usePut) throws IOException {
  583. return upload(url, json, headers, uploadFile, -1, -1, usePut, true);
  584. }
  585. /**
  586. * 根据 url 上传文件
  587. *
  588. * @param url
  589. * @param json payload 负载的消息
  590. * @param headers Http Header
  591. * @param uploadFile
  592. * @return 返回 下载的文件路径
  593. */
  594. public static Map<String, Object> upload(String url,
  595. Map<String, Object> json,
  596. Map<String, String> headers,
  597. File uploadFile,
  598. int connectTimeout,
  599. int socketTimeout,
  600. boolean not200ThrowError) throws IOException {
  601. return upload(url, json, headers, uploadFile, connectTimeout, socketTimeout, false, not200ThrowError);
  602. }
  603. /**
  604. * 根据 url 上传文件
  605. *
  606. * @param url
  607. * @param json payload 负载的消息
  608. * @param headers Http Header
  609. * @param uploadFile
  610. * @param usePut 采用 PUT 请求
  611. * @return 返回 下载的文件路径
  612. */
  613. public static Map<String, Object> upload(String url,
  614. Map<String, Object> json,
  615. Map<String, String> headers,
  616. File uploadFile,
  617. int connectTimeout,
  618. int socketTimeout,
  619. boolean usePut,
  620. boolean not200ThrowError) throws IOException {
  621. // 文件夹 或者 是 文件不存在
  622. if(!uploadFile.exists()) {
  623. throw new FileNotFoundException("upload file: " + uploadFile.getAbsolutePath() + " can not found!");
  624. }
  625. if(uploadFile.isDirectory()) {
  626. throw new IllegalStateException("upload payload must be file, but found directory.");
  627. }
  628. HttpEntityEnclosingRequestBase httpPost = usePut ? new HttpPut(url) : new HttpPost(url);
  629. if(connectTimeout > 0 || socketTimeout >= 0) {
  630. RequestConfig requestConfig = RequestConfig.custom()
  631. .setConnectTimeout(connectTimeout <= 0 ? 30000 : connectTimeout) // 服务器端链接超时设置 30s
  632. .setSocketTimeout(socketTimeout <= 0 ? 10 * 60 * 1000 : socketTimeout) // 上传等待 10 分钟
  633. .build();
  634. httpPost.setConfig(requestConfig);
  635. }
  636. if(headers != null) {
  637. for (Map.Entry<String, String> entry : headers.entrySet()) {
  638. httpPost.setHeader(entry.getKey(), entry.getValue());
  639. }
  640. }
  641. if(json != null && !json.isEmpty()) {
  642. // 有文件上传,并且又负载的消息
  643. MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
  644. multipartEntityBuilder.setCharset(StandardCharsets.UTF_8);
  645. //multipartEntityBuilder.addBinaryBody("file", file,ContentType.create("image/png"),"abc.pdf");
  646. //当设置了setSocketTimeout参数后,以下代码上传PDF不能成功,将setSocketTimeout参数去掉后此可以上传成功。上传图片则没有个限制
  647. //multipartEntityBuilder.addBinaryBody("file",file,ContentType.create("application/octet-stream"),"abd.pdf");
  648. multipartEntityBuilder.addBinaryBody("file", uploadFile);
  649. for (Map.Entry<String, Object> entry : json.entrySet()) {
  650. multipartEntityBuilder.addTextBody(entry.getKey(), (String) entry.getValue());
  651. }
  652. HttpEntity httpEntity = multipartEntityBuilder.build();
  653. httpPost.setEntity(httpEntity);
  654. } else {
  655. // 只有文件上传
  656. FileEntity entity = new FileEntity(uploadFile);
  657. httpPost.setEntity(entity);
  658. }
  659. try (CloseableHttpResponse httpResponse = httpClient.execute(httpPost);){
  660. HttpEntity responseEntity = httpResponse.getEntity();
  661. int statusCode = httpResponse.getStatusLine().getStatusCode();
  662. String result = EntityUtils.toString(responseEntity);
  663. EntityUtils.consume(responseEntity);
  664. if (not200ThrowError && httpResponse.getStatusLine().getStatusCode() != 200) {
  665. throw new IOException(result);
  666. }
  667. Object jsonResult = JSON.parse(result);
  668. JSONObject jsonObject = new JSONObject(2);
  669. if (jsonResult instanceof JSONArray) {
  670. jsonObject.put("result", jsonResult);
  671. } else {
  672. jsonObject = (JSONObject) jsonResult;
  673. }
  674. jsonObject.put("status_code", statusCode);
  675. return jsonObject;
  676. }
  677. }
  678. /**
  679. * 关闭 RPC 调用
  680. *
  681. * @throws IOException
  682. */
  683. public static void shutdown() throws IOException {
  684. httpClient.close();
  685. }
  686. /**
  687. * 下载进度回调
  688. */
  689. public static interface ProcessCall {
  690. /**
  691. * 下载的文件大小
  692. * @param size
  693. */
  694. default void fileSize(long size) {};
  695. /**
  696. * 进度推送
  697. * @param process
  698. */
  699. public void process(float process);
  700. }
  701. static class NoProcessCall implements ProcessCall {
  702. @Override
  703. public void process(float process) {
  704. }
  705. }
  706. }