index.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*!
  2. * axios-miniprogram-adapter 0.3.1 (https://github.com/bigMeow/axios-miniprogram-adapter)
  3. * API https://github.com/bigMeow/axios-miniprogram-adapter/blob/master/doc/api.md
  4. * Copyright 2018-2020 bigMeow. All Rights Reserved
  5. * Licensed under MIT (https://github.com/bigMeow/axios-miniprogram-adapter/blob/master/LICENSE)
  6. */
  7. 'use strict';
  8. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  9. var utils = _interopDefault(require('axios/lib/utils'));
  10. var settle = _interopDefault(require('axios/lib/core/settle'));
  11. var buildURL = _interopDefault(require('axios/lib/helpers/buildURL'));
  12. var buildFullPath = _interopDefault(require('axios/lib/core/buildFullPath'));
  13. var createError = _interopDefault(require('axios/lib/core/createError'));
  14. var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  15. // encoder
  16. function encoder(input) {
  17. var str = String(input);
  18. // initialize result and counter
  19. var block;
  20. var charCode;
  21. var idx = 0;
  22. var map = chars;
  23. var output = '';
  24. for (;
  25. // if the next str index does not exist:
  26. // change the mapping table to "="
  27. // check if d has no fractional digits
  28. str.charAt(idx | 0) || (map = '=', idx % 1);
  29. // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
  30. output += map.charAt(63 & block >> 8 - idx % 1 * 8)) {
  31. charCode = str.charCodeAt(idx += 3 / 4);
  32. if (charCode > 0xFF) {
  33. throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
  34. }
  35. block = block << 8 | charCode;
  36. }
  37. return output;
  38. }
  39. var platFormName = 'wechat';
  40. /**
  41. * 获取各个平台的请求函数
  42. */
  43. function getRequest() {
  44. switch (true) {
  45. case typeof wx === 'object':
  46. platFormName = 'wechat';
  47. return wx.request.bind(wx);
  48. case typeof swan === 'object':
  49. platFormName = 'baidu';
  50. return swan.request.bind(swan);
  51. case typeof my === 'object':
  52. /**
  53. * remark:
  54. * 支付宝客户端已不再维护 my.httpRequest,建议使用 my.request。另外,钉钉客户端尚不支持 my.request。若在钉钉客户端开发小程序,则需要使用 my.httpRequest。
  55. * my.httpRequest的请求头默认值为{'content-type': 'application/x-www-form-urlencoded'}。
  56. * my.request的请求头默认值为{'content-type': 'application/json'}。
  57. * TODO: 区分支付宝和钉钉环境
  58. * 还有个 dd.httpRequest WFK!!! https://ding-doc.dingtalk.com/doc#/dev/httprequest
  59. */
  60. platFormName = 'alipay';
  61. return (my.request || my.httpRequest).bind(my);
  62. default:
  63. return wx.request.bind(wx);
  64. }
  65. }
  66. /**
  67. * 处理各平台返回的响应数据,抹平差异
  68. * @param mpResponse
  69. * @param config axios处理过的请求配置对象
  70. * @param request 小程序的调用发起请求时,传递给小程序api的实际配置
  71. */
  72. function transformResponse(mpResponse, config, mpRequestOption) {
  73. var headers = mpResponse.header || mpResponse.headers;
  74. var status = mpResponse.statusCode || mpResponse.status;
  75. var statusText = '';
  76. if (status === 200) {
  77. statusText = 'OK';
  78. }
  79. else if (status === 400) {
  80. statusText = 'Bad Request';
  81. }
  82. var response = {
  83. data: mpResponse.data,
  84. status: status,
  85. statusText: statusText,
  86. headers: headers,
  87. config: config,
  88. request: mpRequestOption
  89. };
  90. return response;
  91. }
  92. /**
  93. * 处理各平台返回的错误信息,抹平差异
  94. * @param error 小程序api返回的错误对象
  95. * @param reject 上层的promise reject 函数
  96. * @param config
  97. */
  98. function transformError(error, reject, config) {
  99. switch (platFormName) {
  100. case 'wechat':
  101. if (error.errMsg.indexOf('request:fail abort') !== -1) {
  102. // Handle request cancellation (as opposed to a manual cancellation)
  103. reject(createError('Request aborted', config, 'ECONNABORTED', ''));
  104. }
  105. else if (error.errMsg.indexOf('timeout') !== -1) {
  106. // timeout
  107. reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', ''));
  108. }
  109. else {
  110. // NetWordError
  111. reject(createError('Network Error', config, null, ''));
  112. }
  113. break;
  114. case 'alipay':
  115. // https://docs.alipay.com/mini/api/network
  116. if ([14, 19].includes(error.error)) {
  117. reject(createError('Request aborted', config, 'ECONNABORTED', ''));
  118. }
  119. else if ([13].includes(error.error)) {
  120. // timeout
  121. reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', ''));
  122. }
  123. else {
  124. // NetWordError
  125. reject(createError('Network Error', config, null, ''));
  126. }
  127. break;
  128. case 'baidu':
  129. // TODO error.errCode
  130. reject(createError('Network Error', config, null, ''));
  131. break;
  132. }
  133. }
  134. /**
  135. * 将axios的请求配置,转换成各个平台都支持的请求config
  136. * @param config
  137. */
  138. function transformConfig(config) {
  139. if (platFormName === 'alipay') {
  140. config.headers = config.header;
  141. delete config.header;
  142. }
  143. return config;
  144. }
  145. var warn = console.warn;
  146. var isJSONstr = function (str) {
  147. try {
  148. return typeof str === 'string' && str.length && (str = JSON.parse(str)) && Object.prototype.toString.call(str) === '[object Object]';
  149. }
  150. catch (error) {
  151. return false;
  152. }
  153. };
  154. function mpAdapter(config) {
  155. var request = getRequest();
  156. return new Promise(function (resolve, reject) {
  157. var requestTask;
  158. var requestData = config.data;
  159. var requestHeaders = config.headers;
  160. // baidu miniprogram only support upperCase
  161. var requestMethod = (config.method && config.method.toUpperCase()) || 'GET';
  162. // miniprogram network request config
  163. var mpRequestOption = {
  164. method: requestMethod,
  165. url: buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer),
  166. // Listen for success
  167. success: function (mpResponse) {
  168. var response = transformResponse(mpResponse, config, mpRequestOption);
  169. settle(resolve, reject, response);
  170. },
  171. // Handle request Exception
  172. fail: function (error) {
  173. transformError(error, reject, config);
  174. },
  175. complete: function () {
  176. requestTask = undefined;
  177. }
  178. };
  179. // HTTP basic authentication
  180. if (config.auth) {
  181. var _a = [config.auth.username || '', config.auth.password || ''], username = _a[0], password = _a[1];
  182. requestHeaders.Authorization = 'Basic ' + encoder(username + ':' + password);
  183. }
  184. // Set the request timeout
  185. if (config.timeout !== 0) {
  186. warn('The "timeout" option is not supported by miniprogram. For more information about usage see "https://developers.weixin.qq.com/miniprogram/dev/framework/config.html#全局配置"');
  187. }
  188. // Add headers to the request
  189. utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  190. var _header = key.toLowerCase();
  191. if ((typeof requestData === 'undefined' && _header === 'content-type') || _header === 'referer') {
  192. // Remove Content-Type if data is undefined
  193. // And the miniprogram document said that '设置请求的 header,header 中不能设置 Referer'
  194. delete requestHeaders[key];
  195. }
  196. });
  197. mpRequestOption.header = requestHeaders;
  198. // Add responseType to request if needed
  199. if (config.responseType) {
  200. mpRequestOption.responseType = config.responseType;
  201. }
  202. if (config.cancelToken) {
  203. // Handle cancellation
  204. config.cancelToken.promise.then(function onCanceled(cancel) {
  205. if (!requestTask) {
  206. return;
  207. }
  208. requestTask.abort();
  209. reject(cancel);
  210. // Clean up request
  211. requestTask = undefined;
  212. });
  213. }
  214. // Converting JSON strings to objects is handed over to the MiniPrograme
  215. if (isJSONstr(requestData)) {
  216. requestData = JSON.parse(requestData);
  217. }
  218. if (requestData !== undefined) {
  219. mpRequestOption.data = requestData;
  220. }
  221. requestTask = request(transformConfig(mpRequestOption));
  222. });
  223. }
  224. module.exports = mpAdapter;