request.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import axios, { AxiosInstance } from 'axios';
  2. import { ElMessage } from 'element-plus';
  3. import { Local, Session } from '/@/utils/storage';
  4. // 配置新建一个 axios 实例
  5. export const service = axios.create({
  6. baseURL: import.meta.env.VITE_API_URL as any,
  7. timeout: 50000,
  8. headers: { 'Content-Type': 'application/json' },
  9. });
  10. // token 键定义
  11. export const accessTokenKey = 'access-token';
  12. export const refreshAccessTokenKey = `x-${accessTokenKey}`;
  13. // 获取 token
  14. export const getToken = () => {
  15. return Local.get(accessTokenKey);
  16. };
  17. // 清除 token
  18. export const clearAccessTokens = () => {
  19. Local.remove(accessTokenKey);
  20. Local.remove(refreshAccessTokenKey);
  21. // 清除其他
  22. Session.clear();
  23. // 刷新浏览器
  24. window.location.reload();
  25. };
  26. // axios 默认实例
  27. export const axiosInstance: AxiosInstance = axios;
  28. // 添加请求拦截器
  29. service.interceptors.request.use(
  30. (config) => {
  31. // // 在发送请求之前做些什么 token
  32. // if (Session.get('token')) {
  33. // (<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
  34. // }
  35. // 获取本地的 token
  36. const accessToken = Local.get(accessTokenKey);
  37. if (accessToken) {
  38. // 将 token 添加到请求报文头中
  39. config.headers!['Authorization'] = `Bearer ${accessToken}`;
  40. // 判断 accessToken 是否过期
  41. const jwt: any = decryptJWT(accessToken);
  42. const exp = getJWTDate(jwt.exp as number);
  43. // token 已经过期
  44. if (new Date() >= exp) {
  45. // 获取刷新 token
  46. const refreshAccessToken = Local.get(refreshAccessTokenKey);
  47. // 携带刷新 token
  48. if (refreshAccessToken) {
  49. config.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`;
  50. }
  51. }
  52. // debugger
  53. // get请求映射params参数
  54. if (config.method?.toLowerCase() === 'get' && config.data) {
  55. let url = config.url + '?' + tansParams(config.data);
  56. url = url.slice(0, -1);
  57. config.data = {};
  58. config.url = url;
  59. }
  60. }
  61. return config;
  62. },
  63. (error) => {
  64. // 对请求错误做些什么
  65. return Promise.reject(error);
  66. }
  67. );
  68. // 添加响应拦截器
  69. service.interceptors.response.use(
  70. (res) => {
  71. // 获取状态码和返回数据
  72. var status = res.status;
  73. var serve = res.data;
  74. // 处理 401
  75. if (status === 401) {
  76. clearAccessTokens();
  77. }
  78. // 处理未进行规范化处理的
  79. if (status >= 400) {
  80. throw new Error(res.statusText || 'Request Error.');
  81. }
  82. // 处理规范化结果错误
  83. if (serve && serve.hasOwnProperty('errors') && serve.errors) {
  84. throw new Error(JSON.stringify(serve.errors || 'Request Error.'));
  85. }
  86. // 读取响应报文头 token 信息
  87. var accessToken = res.headers[accessTokenKey];
  88. var refreshAccessToken = res.headers[refreshAccessTokenKey];
  89. // 判断是否是无效 token
  90. if (accessToken === 'invalid_token') {
  91. clearAccessTokens();
  92. }
  93. // 判断是否存在刷新 token,如果存在则存储在本地
  94. else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
  95. Local.set(accessTokenKey, accessToken);
  96. Local.set(refreshAccessTokenKey, refreshAccessToken);
  97. }
  98. // 响应拦截及自定义处理
  99. if (serve.code === 401) {
  100. clearAccessTokens();
  101. } else if (serve.code === undefined) {
  102. return Promise.resolve(res);
  103. } else if (serve.code !== 200) {
  104. var message = JSON.stringify(serve.message);
  105. ElMessage.error(message);
  106. throw new Error(message);
  107. }
  108. return res;
  109. },
  110. (error) => {
  111. // 处理响应错误
  112. if (error.response) {
  113. if (error.response.status === 401) {
  114. clearAccessTokens();
  115. }
  116. }
  117. // 对响应错误做点什么
  118. if (error.message.indexOf('timeout') != -1) {
  119. ElMessage.error('网络超时');
  120. } else if (error.message == 'Network Error') {
  121. ElMessage.error('网络连接错误');
  122. } else {
  123. if (error.response.data) ElMessage.error(error.response.statusText);
  124. else ElMessage.error('接口路径找不到');
  125. }
  126. return Promise.reject(error);
  127. }
  128. );
  129. /**
  130. * 参数处理
  131. * @param {*} params 参数
  132. */
  133. export function tansParams(params: any) {
  134. let result = '';
  135. for (const propName of Object.keys(params)) {
  136. const value = params[propName];
  137. var part = encodeURIComponent(propName) + '=';
  138. if (value !== null && value !== '' && typeof value !== 'undefined') {
  139. if (typeof value === 'object') {
  140. for (const key of Object.keys(value)) {
  141. if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
  142. let params = propName + '[' + key + ']';
  143. var subPart = encodeURIComponent(params) + '=';
  144. result += subPart + encodeURIComponent(value[key]) + '&';
  145. }
  146. }
  147. } else {
  148. result += part + encodeURIComponent(value) + '&';
  149. }
  150. }
  151. }
  152. return result;
  153. }
  154. /**
  155. * 解密 JWT token 的信息
  156. * @param token jwt token 字符串
  157. * @returns <any>object
  158. */
  159. export function decryptJWT(token: string): any {
  160. token = token.replace(/_/g, '/').replace(/-/g, '+');
  161. var json = decodeURIComponent(escape(window.atob(token.split('.')[1])));
  162. return JSON.parse(json);
  163. }
  164. /**
  165. * 将 JWT 时间戳转换成 Date
  166. * @description 主要针对 `exp`,`iat`,`nbf`
  167. * @param timestamp 时间戳
  168. * @returns Date 对象
  169. */
  170. export function getJWTDate(timestamp: number): Date {
  171. return new Date(timestamp * 1000);
  172. }
  173. // 导出 axios 实例
  174. export default service;