request.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import fetch from 'dva/fetch';
  2. import { message, notification } from 'antd';
  3. import router from 'umi/router';
  4. import hash from 'hash.js';
  5. import { isAntdPro, getToken, GetTokenFromUrl, storeToken } from './utils';
  6. // var apiUrl = "http://oraysmart.com:8888"
  7. // var apiUrl = "http://120.55.44.4:8900"
  8. //节流阀
  9. let flag = false;
  10. let tokenFlag = false;
  11. const checkStatus = response => {
  12. if (response.status >= 200 && response.status < 300) {
  13. return response;
  14. }
  15. // if (
  16. // response.status == 400 ||
  17. // response.status == 401 ||
  18. // response.status == 601 ||
  19. // response.status == 602
  20. // ) {
  21. // response
  22. // .json()
  23. // .then(body => {
  24. // notification.error({
  25. // message: '错误',
  26. // description: `${body.msg}-${body.data}: ${response.url}`,
  27. // });
  28. // })
  29. // .catch(err => {
  30. // notification.error({
  31. // message: '错误',
  32. // description: 'token失效,请重新登录',
  33. // });
  34. // });
  35. // return response;
  36. // }
  37. // if (response.status === 600) {
  38. // return response;
  39. // }
  40. const error = new Error(response.data);
  41. error.name = response.status;
  42. error.response = response;
  43. console.error(error);
  44. // throw error;
  45. return Promise.reject();
  46. };
  47. const cachedSave = response => {
  48. if (response.status === 600) return response;
  49. /**
  50. * Clone a response data and store it in sessionStorage
  51. * Does not support data other than json, Cache only json
  52. */
  53. const contentType = response.headers.get('Content-Type');
  54. if (contentType && contentType.match(/application\/json/i)) {
  55. // All data is saved as text
  56. response
  57. .clone()
  58. .text()
  59. .then(() => {
  60. // sessionStorage.setItem(hashcode, content);
  61. // sessionStorage.setItem(`${hashcode}:timestamp`, Date.now());
  62. });
  63. }
  64. return response;
  65. };
  66. /**
  67. * Requests a URL, returning a promise.
  68. *
  69. * @param {string} url The URL we want to request
  70. * @param {object} [option] The options we want to pass to "fetch"
  71. * @return {object} An object containing either "data" or "err"
  72. */
  73. export default function request(url, option, jwt) {
  74. const number = new Date().getTime();
  75. // console.log(API_HOST);
  76. const time = url.indexOf('?') > -1 ? `&time=${number}` : `?time=${number}`;
  77. if (url.indexOf('http://') == -1 && url.indexOf('https://') == -1) {
  78. if (
  79. url.indexOf('/api/v') === -1 &&
  80. url.indexOf('/api/supplier') === -1 &&
  81. url.indexOf('/api/contract') === -1
  82. ) {
  83. url = `/api/v1${url}${time}`;
  84. }
  85. // API_HOST在config/config.js的define中配置
  86. // url = API_HOST + url
  87. }
  88. let token = getToken();
  89. if (!token) {
  90. token = GetTokenFromUrl();
  91. storeToken(token);
  92. }
  93. const options = {
  94. expirys: isAntdPro(),
  95. ...option,
  96. };
  97. /**
  98. * Produce fingerprints based on url and parameters
  99. * Maybe url has the same parameters
  100. */
  101. const fingerprint = url + (options.body ? JSON.stringify(options.body) : '');
  102. const hashcode = hash
  103. .sha256()
  104. .update(fingerprint)
  105. .digest('hex');
  106. const defaultOptions = {
  107. credentials: 'include',
  108. };
  109. const newOptions = { ...defaultOptions, ...options };
  110. newOptions.headers = {
  111. ...newOptions.headers,
  112. 'JWT-TOKEN': jwt ? jwt : `${token}`,
  113. };
  114. if (
  115. newOptions.method === 'POST' ||
  116. newOptions.method === 'PUT' ||
  117. newOptions.method === 'DELETE'
  118. ) {
  119. if (!(newOptions.body instanceof FormData)) {
  120. newOptions.headers = {
  121. Accept: 'application/json',
  122. 'Content-Type': 'application/json;charset=utf-8',
  123. ...newOptions.headers,
  124. };
  125. newOptions.body = JSON.stringify(newOptions.body);
  126. } else {
  127. // newOptions.body is FormData
  128. newOptions.headers = {
  129. Accept: 'application/json',
  130. ...newOptions.headers,
  131. };
  132. }
  133. }
  134. const expirys = options.expirys && 60;
  135. // options.expirys !== false, return the cache,
  136. if (options.expirys !== false) {
  137. const cached = sessionStorage.getItem(hashcode);
  138. const whenCached = sessionStorage.getItem(`${hashcode}:timestamp`);
  139. if (cached !== null && whenCached !== null) {
  140. const age = (Date.now() - whenCached) / 1000;
  141. if (age < expirys) {
  142. const response = new Response(new Blob([cached]));
  143. return response.json();
  144. }
  145. sessionStorage.removeItem(hashcode);
  146. sessionStorage.removeItem(`${hashcode}:timestamp`);
  147. }
  148. }
  149. return fetch(url, newOptions)
  150. .then(checkStatus)
  151. .then(response => cachedSave(response, hashcode))
  152. .then(response => {
  153. // DELETE and 204 do not return data by default
  154. // using .json will report an error.
  155. if (response.status === 204) {
  156. return response.text();
  157. }
  158. // if (response.status === 600) {
  159. // return response;
  160. // } else {
  161. return response.json();
  162. // }
  163. })
  164. .then(response => {
  165. let code = response.code;
  166. if (typeof response === 'string') {
  167. return response;
  168. } else if (code !== 200) {
  169. if (code === 401 || code === 601 || code === 602) {
  170. if (tokenFlag) return false;
  171. // 用户token出错,重定向
  172. tokenFlag = true;
  173. setTimeout(() => {
  174. tokenFlag = false;
  175. }, 3000);
  176. notification.error({
  177. message: '错误',
  178. description: 'token失效,请重新登录',
  179. });
  180. router.push(`/login?referrer=${encodeURIComponent(encodeURIComponent(location.href))}`);
  181. } else {
  182. if (flag) return false;
  183. flag = true;
  184. setTimeout(() => {
  185. flag = false;
  186. }, 3000);
  187. message.error(response.msg);
  188. }
  189. return false;
  190. } else {
  191. return response;
  192. }
  193. })
  194. .catch(e => {
  195. const status = e?.name;
  196. // environment should not be used
  197. if (status === 401 || status === 601 || status === 602 || status === 400) {
  198. if (tokenFlag) return false;
  199. // 用户token出错,重定向
  200. tokenFlag = true;
  201. setTimeout(() => {
  202. tokenFlag = false;
  203. }, 3000);
  204. // 用户token出错,重定向
  205. notification.error({
  206. message: '错误',
  207. description: 'token失效,请重新登录',
  208. });
  209. router.push(`/login?referrer=${encodeURIComponent(encodeURIComponent(location.href))}`);
  210. return;
  211. } else if (status == 'AbortError') {
  212. // 中止的ajax 不做额外处理
  213. return e;
  214. }
  215. // if (status <= 504 && status > 500 && status !== 600) {
  216. // router.push('/exception/500');
  217. // throw e;
  218. // }
  219. // if (status >= 404 && status < 422) {
  220. // router.push('/exception/404');
  221. // throw e;
  222. // }
  223. // if (status === 600) {
  224. // throw e;
  225. // }
  226. notification.error({
  227. message: '错误',
  228. description: `网络连接异常,请检查网络后重试`,
  229. // description: `HTTP请求错误,错误码:${status};接口地址${url}`,
  230. });
  231. throw e;
  232. });
  233. }