WxMpServiceImpl.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. package me.chanjar.weixin.mp.api;
  2. import com.google.gson.JsonElement;
  3. import com.google.gson.JsonObject;
  4. import com.google.gson.internal.Streams;
  5. import com.google.gson.reflect.TypeToken;
  6. import com.google.gson.stream.JsonReader;
  7. import me.chanjar.weixin.common.bean.WxAccessToken;
  8. import me.chanjar.weixin.common.bean.WxMenu;
  9. import me.chanjar.weixin.common.bean.result.WxError;
  10. import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
  11. import me.chanjar.weixin.common.exception.WxErrorException;
  12. import me.chanjar.weixin.common.session.StandardSessionManager;
  13. import me.chanjar.weixin.common.session.WxSessionManager;
  14. import me.chanjar.weixin.common.util.StringUtils;
  15. import me.chanjar.weixin.common.util.crypto.SHA1;
  16. import me.chanjar.weixin.common.util.fs.FileUtils;
  17. import me.chanjar.weixin.common.util.http.*;
  18. import me.chanjar.weixin.common.util.json.GsonHelper;
  19. import me.chanjar.weixin.mp.bean.*;
  20. import me.chanjar.weixin.mp.bean.result.*;
  21. import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor;
  22. import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
  23. import org.apache.http.HttpHost;
  24. import org.apache.http.auth.AuthScope;
  25. import org.apache.http.auth.UsernamePasswordCredentials;
  26. import org.apache.http.client.ClientProtocolException;
  27. import org.apache.http.client.CredentialsProvider;
  28. import org.apache.http.client.config.RequestConfig;
  29. import org.apache.http.client.methods.CloseableHttpResponse;
  30. import org.apache.http.client.methods.HttpGet;
  31. import org.apache.http.impl.client.BasicCredentialsProvider;
  32. import org.apache.http.impl.client.BasicResponseHandler;
  33. import org.apache.http.impl.client.CloseableHttpClient;
  34. import org.apache.http.impl.client.HttpClients;
  35. import org.slf4j.Logger;
  36. import org.slf4j.LoggerFactory;
  37. import java.io.File;
  38. import java.io.IOException;
  39. import java.io.InputStream;
  40. import java.io.StringReader;
  41. import java.security.NoSuchAlgorithmException;
  42. import java.util.List;
  43. import java.util.UUID;
  44. public class WxMpServiceImpl implements WxMpService {
  45. protected final Logger log = LoggerFactory.getLogger(WxMpServiceImpl.class);
  46. /**
  47. * 全局的是否正在刷新access token的锁
  48. */
  49. protected final Object globalAccessTokenRefreshLock = new Object();
  50. /**
  51. * 全局的是否正在刷新jsapi_ticket的锁
  52. */
  53. protected final Object globalJsapiTicketRefreshLock = new Object();
  54. protected WxMpConfigStorage wxMpConfigStorage;
  55. protected CloseableHttpClient httpClient;
  56. protected HttpHost httpProxy;
  57. private int retrySleepMillis = 1000;
  58. private int maxRetryTimes = 5;
  59. protected WxSessionManager sessionManager = new StandardSessionManager();
  60. public boolean checkSignature(String timestamp, String nonce, String signature) {
  61. try {
  62. return SHA1.gen(wxMpConfigStorage.getToken(), timestamp, nonce).equals(signature);
  63. } catch (Exception e) {
  64. return false;
  65. }
  66. }
  67. public String getAccessToken() throws WxErrorException {
  68. return getAccessToken(false);
  69. }
  70. public String getAccessToken(boolean forceRefresh) throws WxErrorException {
  71. if (forceRefresh) {
  72. wxMpConfigStorage.expireAccessToken();
  73. }
  74. if (wxMpConfigStorage.isAccessTokenExpired()) {
  75. synchronized (globalAccessTokenRefreshLock) {
  76. if (wxMpConfigStorage.isAccessTokenExpired()) {
  77. String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
  78. + "&appid=" + wxMpConfigStorage.getAppId()
  79. + "&secret=" + wxMpConfigStorage.getSecret()
  80. ;
  81. try {
  82. HttpGet httpGet = new HttpGet(url);
  83. if (httpProxy != null) {
  84. RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
  85. httpGet.setConfig(config);
  86. }
  87. CloseableHttpClient httpclient = getHttpclient();
  88. CloseableHttpResponse response = httpclient.execute(httpGet);
  89. String resultContent = new BasicResponseHandler().handleResponse(response);
  90. WxError error = WxError.fromJson(resultContent);
  91. if (error.getErrorCode() != 0) {
  92. throw new WxErrorException(error);
  93. }
  94. WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
  95. wxMpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
  96. } catch (ClientProtocolException e) {
  97. throw new RuntimeException(e);
  98. } catch (IOException e) {
  99. throw new RuntimeException(e);
  100. }
  101. }
  102. }
  103. }
  104. return wxMpConfigStorage.getAccessToken();
  105. }
  106. public String getJsapiTicket() throws WxErrorException {
  107. return getJsapiTicket(false);
  108. }
  109. public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
  110. if (forceRefresh) {
  111. wxMpConfigStorage.expireJsapiTicket();
  112. }
  113. if (wxMpConfigStorage.isJsapiTicketExpired()) {
  114. synchronized (globalJsapiTicketRefreshLock) {
  115. if (wxMpConfigStorage.isJsapiTicketExpired()) {
  116. String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
  117. String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
  118. JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
  119. JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
  120. String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
  121. int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
  122. wxMpConfigStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
  123. }
  124. }
  125. }
  126. return wxMpConfigStorage.getJsapiTicket();
  127. }
  128. public String createJsapiSignature(long timestamp, String noncestr, String url) throws WxErrorException {
  129. String jsapiTicket = getJsapiTicket(false);
  130. try {
  131. return SHA1.genWithAmple(
  132. "jsapi_ticket=" + jsapiTicket,
  133. "noncestr=" + noncestr,
  134. "timestamp=" + timestamp,
  135. "url=" + url
  136. );
  137. } catch (NoSuchAlgorithmException e) {
  138. throw new RuntimeException(e);
  139. }
  140. }
  141. public void customMessageSend(WxMpCustomMessage message) throws WxErrorException {
  142. String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
  143. execute(new SimplePostRequestExecutor(), url, message.toJson());
  144. }
  145. public void menuCreate(WxMenu menu) throws WxErrorException {
  146. String url = "https://api.weixin.qq.com/cgi-bin/menu/create";
  147. execute(new SimplePostRequestExecutor(), url, menu.toJson());
  148. }
  149. public void menuDelete() throws WxErrorException {
  150. String url = "https://api.weixin.qq.com/cgi-bin/menu/delete";
  151. execute(new SimpleGetRequestExecutor(), url, null);
  152. }
  153. public WxMenu menuGet() throws WxErrorException {
  154. String url = "https://api.weixin.qq.com/cgi-bin/menu/get";
  155. try {
  156. String resultContent = execute(new SimpleGetRequestExecutor(), url, null);
  157. return WxMenu.fromJson(resultContent);
  158. } catch (WxErrorException e) {
  159. // 46003 不存在的菜单数据
  160. if (e.getError().getErrorCode() == 46003) {
  161. return null;
  162. }
  163. throw e;
  164. }
  165. }
  166. public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException {
  167. return mediaUpload(mediaType,FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
  168. }
  169. public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
  170. String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType;
  171. return execute(new MediaUploadRequestExecutor(), url, file);
  172. }
  173. public File mediaDownload(String media_id) throws WxErrorException {
  174. String url = "http://file.api.weixin.qq.com/cgi-bin/media/get";
  175. return execute(new MediaDownloadRequestExecutor(), url, "media_id=" + media_id);
  176. }
  177. public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException {
  178. String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews";
  179. String responseContent = execute(new SimplePostRequestExecutor(), url, news.toJson());
  180. return WxMpMassUploadResult.fromJson(responseContent);
  181. }
  182. public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException {
  183. String url = "http://file.api.weixin.qq.com/cgi-bin/media/uploadvideo";
  184. String responseContent = execute(new SimplePostRequestExecutor(), url, video.toJson());
  185. return WxMpMassUploadResult.fromJson(responseContent);
  186. }
  187. public WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException {
  188. String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall";
  189. String responseContent = execute(new SimplePostRequestExecutor(), url, message.toJson());
  190. return WxMpMassSendResult.fromJson(responseContent);
  191. }
  192. public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException {
  193. String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send";
  194. String responseContent = execute(new SimplePostRequestExecutor(), url, message.toJson());
  195. return WxMpMassSendResult.fromJson(responseContent);
  196. }
  197. public WxMpGroup groupCreate(String name) throws WxErrorException {
  198. String url = "https://api.weixin.qq.com/cgi-bin/groups/create";
  199. JsonObject json = new JsonObject();
  200. JsonObject groupJson = new JsonObject();
  201. json.add("group", groupJson);
  202. groupJson.addProperty("name", name);
  203. String responseContent = execute(
  204. new SimplePostRequestExecutor(),
  205. url,
  206. json.toString());
  207. return WxMpGroup.fromJson(responseContent);
  208. }
  209. public List<WxMpGroup> groupGet() throws WxErrorException {
  210. String url = "https://api.weixin.qq.com/cgi-bin/groups/get";
  211. String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
  212. /*
  213. * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} }
  214. * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
  215. */
  216. JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
  217. return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), new TypeToken<List<WxMpGroup>>(){}.getType());
  218. }
  219. public long userGetGroup(String openid) throws WxErrorException {
  220. String url = "https://api.weixin.qq.com/cgi-bin/groups/getid";
  221. JsonObject o = new JsonObject();
  222. o.addProperty("openid", openid);
  223. String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString());
  224. JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
  225. return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid"));
  226. }
  227. public void groupUpdate(WxMpGroup group) throws WxErrorException {
  228. String url = "https://api.weixin.qq.com/cgi-bin/groups/update";
  229. execute(new SimplePostRequestExecutor(), url, group.toJson());
  230. }
  231. public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException {
  232. String url = "https://api.weixin.qq.com/cgi-bin/groups/members/update";
  233. JsonObject json = new JsonObject();
  234. json.addProperty("openid", openid);
  235. json.addProperty("to_groupid", to_groupid);
  236. execute(new SimplePostRequestExecutor(), url, json.toString());
  237. }
  238. public void userUpdateRemark(String openid, String remark) throws WxErrorException {
  239. String url = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark";
  240. JsonObject json = new JsonObject();
  241. json.addProperty("openid", openid);
  242. json.addProperty("remark", remark);
  243. execute(new SimplePostRequestExecutor(), url, json.toString());
  244. }
  245. public WxMpUser userInfo(String openid, String lang) throws WxErrorException {
  246. String url = "https://api.weixin.qq.com/cgi-bin/user/info";
  247. lang = lang == null ? "zh_CN" : lang;
  248. String responseContent = execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang);
  249. return WxMpUser.fromJson(responseContent);
  250. }
  251. public WxMpUserList userList(String next_openid) throws WxErrorException {
  252. String url = "https://api.weixin.qq.com/cgi-bin/user/get";
  253. String responseContent = execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid);
  254. return WxMpUserList.fromJson(responseContent);
  255. }
  256. public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
  257. String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
  258. JsonObject json = new JsonObject();
  259. json.addProperty("action_name", "QR_SCENE");
  260. if(expire_seconds != null) {
  261. json.addProperty("expire_seconds", expire_seconds);
  262. }
  263. JsonObject actionInfo = new JsonObject();
  264. JsonObject scene = new JsonObject();
  265. scene.addProperty("scene_id", scene_id);
  266. actionInfo.add("scene", scene);
  267. json.add("action_info", actionInfo);
  268. String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
  269. return WxMpQrCodeTicket.fromJson(responseContent);
  270. }
  271. public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
  272. String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
  273. JsonObject json = new JsonObject();
  274. json.addProperty("action_name", "QR_LIMIT_SCENE");
  275. JsonObject actionInfo = new JsonObject();
  276. JsonObject scene = new JsonObject();
  277. scene.addProperty("scene_id", scene_id);
  278. actionInfo.add("scene", scene);
  279. json.add("action_info", actionInfo);
  280. String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
  281. return WxMpQrCodeTicket.fromJson(responseContent);
  282. }
  283. public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
  284. String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
  285. return execute(new QrCodeRequestExecutor(), url, ticket);
  286. }
  287. public String shortUrl(String long_url) throws WxErrorException {
  288. String url = "https://api.weixin.qq.com/cgi-bin/shorturl";
  289. JsonObject o = new JsonObject();
  290. o.addProperty("action", "long2short");
  291. o.addProperty("long_url", long_url);
  292. String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString());
  293. JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
  294. return tmpJsonElement.getAsJsonObject().get("short_url").getAsString();
  295. }
  296. public String templateSend(WxMpTemplateMessage templateMessage) throws WxErrorException {
  297. String url = "https://api.weixin.qq.com/cgi-bin/message/template/send";
  298. String responseContent = execute(new SimplePostRequestExecutor(), url, templateMessage.toJson());
  299. JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
  300. return tmpJsonElement.getAsJsonObject().get("msgid").getAsString();
  301. }
  302. public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException {
  303. String url = "https://api.weixin.qq.com/semantic/semproxy/search";
  304. String responseContent = execute(new SimplePostRequestExecutor(), url, semanticQuery.toJson());
  305. return WxMpSemanticQueryResult.fromJson(responseContent);
  306. }
  307. @Override
  308. public String oauth2buildAuthorizationUrl(String scope, String state) {
  309. String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" ;
  310. url += "appid=" + wxMpConfigStorage.getAppId();
  311. url += "&redirect_uri=" + URIUtil.encodeURIComponent(wxMpConfigStorage.getOauth2redirectUri());
  312. url += "&response_type=code";
  313. url += "&scope=" + scope;
  314. if (state != null) {
  315. url += "&state=" + state;
  316. }
  317. url += "#wechat_redirect";
  318. return url;
  319. }
  320. @Override
  321. public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
  322. String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
  323. url += "appid=" + wxMpConfigStorage.getAppId();
  324. url += "&secret=" + wxMpConfigStorage.getSecret();
  325. url += "&code=" + code;
  326. url += "&grant_type=authorization_code";
  327. try {
  328. RequestExecutor<String, String> executor = new SimpleGetRequestExecutor();
  329. String responseText = executor.execute(getHttpclient(), httpProxy, url, null);
  330. return WxMpOAuth2AccessToken.fromJson(responseText);
  331. } catch (ClientProtocolException e) {
  332. throw new RuntimeException(e);
  333. } catch (IOException e) {
  334. throw new RuntimeException(e);
  335. }
  336. }
  337. @Override
  338. public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException {
  339. String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?";
  340. url += "appid=" + wxMpConfigStorage.getAppId();
  341. url += "&grant_type=refresh_token";
  342. url += "&refresh_token=" + refreshToken;
  343. try {
  344. RequestExecutor<String, String> executor = new SimpleGetRequestExecutor();
  345. String responseText = executor.execute(getHttpclient(), httpProxy, url, null);
  346. return WxMpOAuth2AccessToken.fromJson(responseText);
  347. } catch (ClientProtocolException e) {
  348. throw new RuntimeException(e);
  349. } catch (IOException e) {
  350. throw new RuntimeException(e);
  351. }
  352. }
  353. @Override
  354. public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException {
  355. String url = "https://api.weixin.qq.com/sns/userinfo?";
  356. url += "access_token=" + oAuth2AccessToken.getAccessToken();
  357. url += "&openid=" + oAuth2AccessToken.getOpenId();
  358. if (lang == null) {
  359. url += "&lang=zh_CN";
  360. } else {
  361. url += "&lang=" + lang;
  362. }
  363. try {
  364. RequestExecutor<String, String> executor = new SimpleGetRequestExecutor();
  365. String responseText = executor.execute(getHttpclient(), httpProxy, url, null);
  366. return WxMpUser.fromJson(responseText);
  367. } catch (ClientProtocolException e) {
  368. throw new RuntimeException(e);
  369. } catch (IOException e) {
  370. throw new RuntimeException(e);
  371. }
  372. }
  373. @Override
  374. public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) {
  375. String url = "https://api.weixin.qq.com/sns/auth?";
  376. url += "access_token=" + oAuth2AccessToken;
  377. url += "&openid=" + oAuth2AccessToken.getOpenId();
  378. try {
  379. RequestExecutor<String, String> executor = new SimpleGetRequestExecutor();
  380. executor.execute(getHttpclient(), httpProxy, url, null);
  381. } catch (ClientProtocolException e) {
  382. throw new RuntimeException(e);
  383. } catch (IOException e) {
  384. throw new RuntimeException(e);
  385. } catch (WxErrorException e) {
  386. return false;
  387. }
  388. return true;
  389. }
  390. public String get(String url, String queryParam) throws WxErrorException {
  391. return execute(new SimpleGetRequestExecutor(), url, queryParam);
  392. }
  393. public String post(String url, String postData) throws WxErrorException {
  394. return execute(new SimplePostRequestExecutor(), url, postData);
  395. }
  396. /**
  397. * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
  398. * @param executor
  399. * @param uri
  400. * @param data
  401. * @return
  402. * @throws WxErrorException
  403. */
  404. public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
  405. int retryTimes = 0;
  406. do {
  407. try {
  408. return executeInternal(executor, uri, data);
  409. } catch (WxErrorException e) {
  410. WxError error = e.getError();
  411. /**
  412. * -1 系统繁忙, 1000ms后重试
  413. */
  414. if (error.getErrorCode() == -1) {
  415. int sleepMillis = retrySleepMillis * (1 << retryTimes);
  416. try {
  417. log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
  418. Thread.sleep(sleepMillis);
  419. } catch (InterruptedException e1) {
  420. throw new RuntimeException(e1);
  421. }
  422. } else {
  423. throw e;
  424. }
  425. }
  426. } while(++retryTimes < maxRetryTimes);
  427. throw new RuntimeException("微信服务端异常,超出重试次数");
  428. }
  429. protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
  430. String accessToken = getAccessToken(false);
  431. String uriWithAccessToken = uri;
  432. uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;
  433. try {
  434. return executor.execute(getHttpclient(), httpProxy, uriWithAccessToken, data);
  435. } catch (WxErrorException e) {
  436. WxError error = e.getError();
  437. /*
  438. * 发生以下情况时尝试刷新access_token
  439. * 40001 获取access_token时AppSecret错误,或者access_token无效
  440. * 42001 access_token超时
  441. */
  442. if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
  443. // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
  444. wxMpConfigStorage.expireAccessToken();
  445. return execute(executor, uri, data);
  446. }
  447. if (error.getErrorCode() != 0) {
  448. throw new WxErrorException(error);
  449. }
  450. return null;
  451. } catch (ClientProtocolException e) {
  452. throw new RuntimeException(e);
  453. } catch (IOException e) {
  454. throw new RuntimeException(e);
  455. }
  456. }
  457. protected CloseableHttpClient getHttpclient() {
  458. return httpClient;
  459. }
  460. public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
  461. this.wxMpConfigStorage = wxConfigProvider;
  462. String http_proxy_host = wxMpConfigStorage.getHttp_proxy_host();
  463. int http_proxy_port = wxMpConfigStorage.getHttp_proxy_port();
  464. String http_proxy_username = wxMpConfigStorage.getHttp_proxy_username();
  465. String http_proxy_password = wxMpConfigStorage.getHttp_proxy_password();
  466. if(StringUtils.isNotBlank(http_proxy_host)) {
  467. // 使用代理服务器
  468. if(StringUtils.isNotBlank(http_proxy_username)) {
  469. // 需要用户认证的代理服务器
  470. CredentialsProvider credsProvider = new BasicCredentialsProvider();
  471. credsProvider.setCredentials(
  472. new AuthScope(http_proxy_host, http_proxy_port),
  473. new UsernamePasswordCredentials(http_proxy_username, http_proxy_password));
  474. httpClient = HttpClients
  475. .custom()
  476. .setDefaultCredentialsProvider(credsProvider)
  477. .build();
  478. } else {
  479. // 无需用户认证的代理服务器
  480. httpClient = HttpClients.createDefault();
  481. }
  482. httpProxy = new HttpHost(http_proxy_host, http_proxy_port);
  483. } else {
  484. httpClient = HttpClients.createDefault();
  485. }
  486. }
  487. @Override
  488. public void setRetrySleepMillis(int retrySleepMillis) {
  489. this.retrySleepMillis = retrySleepMillis;
  490. }
  491. @Override
  492. public void setMaxRetryTimes(int maxRetryTimes) {
  493. this.maxRetryTimes = maxRetryTimes;
  494. }
  495. }