• 基于axios 的二次封装


    1.封装目的

    此次进行简单的封装,所以暂时没有考虑取消重复请求、重复发送请求、请求缓存等情况!这里主要实现以下目的:

    1. 实现请求拦截
    2. 实现响应拦截
    3. 常见错误信息处理
    4. 请求头设置
    5. api 集中式管理

    2.初始化 axios 实例 

    请求拦截器

            发送请求之前运行一般会判断是否有token,如果token存在则在请求头加上这个token。服务端会判断我这个token是否过期。可以设置加载全局loading。等

    响应拦截器

            对服务端返回的数据进行处理,存储token,错误处理、登录、登录失效路由跳转、关闭全局loading等。

    目录结构如下:

     index.js代码如下

    1. /*
    2. * @Description:
    3. * @Version: 2.0
    4. * @Autor: Cookie
    5. * @Date: 2022-06-28 11:33:32
    6. * @LastEditors: Zhang
    7. * @LastEditTime: 2022-06-28 15:38:21
    8. */
    9. import serverConfig from "./config";
    10. import axios from 'axios'
    11. import qs from "qs";
    12. import { Message, Loading, MessageBox } from 'element-ui';
    13. // loading函数
    14. // 记录请求次数
    15. let needLoadingRequestCount = 0;
    16. let loading;
    17. function startLoading() {
    18. loading = Loading.service({
    19. lock: true,
    20. text: '加载中……',
    21. background: 'rgba(0, 0, 0, 0.5)',
    22. });
    23. }
    24. function endLoading() {
    25. // 延迟500ms,防止网速特快加载中画面一闪而过
    26. setTimeout(function () {
    27. if (loading) loading.close();
    28. }, 500);
    29. }
    30. // 打开loading
    31. function showFullScreenLoading() {
    32. if (needLoadingRequestCount === 0) {
    33. startLoading();
    34. }
    35. needLoadingRequestCount++;
    36. }
    37. // 关闭loading
    38. function tryHideFullScreenLoading() {
    39. if (needLoadingRequestCount <= 0) return;
    40. needLoadingRequestCount--;
    41. if (needLoadingRequestCount === 0) {
    42. endLoading();
    43. }
    44. }
    45. // 创建实例
    46. const serviceAxios = axios.create({
    47. baseURL: serverConfig.baseURL, // 基础请求地址
    48. timeout: 10000, // 请求超时设置
    49. // withCredentials: false, // 跨域请求是否需要携带 cookie
    50. });
    51. // 添加请求拦截器
    52. serviceAxios.interceptors.request.use(
    53. config => {
    54. // 在发送请求之前做些什么
    55. // 打开loading
    56. showFullScreenLoading();
    57. // 如果开启 token 认证
    58. if (serverConfig.useTokenAuthorization) {
    59. config.headers["Authorization"] = JSON.parse(localStorage.getItem("token")); // 请求头携带 token
    60. }
    61. // axios.defaults.headers.common['Authorization'] = localStorage.getItem("token")
    62. // 设置请求头
    63. if (!config.headers["content-type"]) { // 如果没有设置请求头
    64. if (config.method === 'post') {
    65. config.headers["content-type"] = "application/x-www-form-urlencoded"; // post 请求
    66. config.data = qs.stringify(config.data); // 序列化,比如表单数据
    67. } else {
    68. config.headers["content-type"] = "application/json"; // 默认类型(get)
    69. // axios.defaults.headers.post['Content-Type'] = 'application/json';
    70. }
    71. }
    72. console.log("请求配置", config);
    73. return config;
    74. },
    75. error => {
    76. // 对请求错误做些什么
    77. // 关闭loading
    78. tryHideFullScreenLoading();
    79. return Promise.reject(error);
    80. }
    81. );
    82. // 添加响应拦截器
    83. serviceAxios.interceptors.response.use(
    84. res => {
    85. console.log('响应', res)
    86. // 关闭loading
    87. tryHideFullScreenLoading();
    88. let data = res.data
    89. if (!res.success) {
    90. // B002:Token 过期了;
    91. if (res.code === 'B002') {
    92. // 最后一次出弹框
    93. if (needLoadingRequestCount === 0) {
    94. MessageBox.confirm(
    95. `你已被登出,可以取消继续留在该页面,
    96. 或者重新登录, 确定登出`,
    97. {
    98. confirmButtonText: '重新登录',
    99. cancelButtonText: '取消',
    100. type: 'warning',
    101. },
    102. ).then(() => {
    103. // 返回登录页
    104. // ...做些事情
    105. // 为了重新实例化vue-router对象 避免bug
    106. location.reload();
    107. });
    108. }
    109. } else {
    110. Message({
    111. message: res.msg,
    112. type: 'error',
    113. });
    114. }
    115. }
    116. // 对响应数据做点什么
    117. return data;
    118. },
    119. error => {
    120. console.log('响应fail', error)
    121. // 对响应错误做点什么
    122. let message = "";
    123. if (error && error.response) {
    124. switch (error.response.status) {
    125. case 302:
    126. message = "接口重定向了!";
    127. break;
    128. case 400:
    129. message = "参数不正确!";
    130. break;
    131. case 401:
    132. message = "您未登录,或者登录已经超时,请先登录!";
    133. break;
    134. case 403:
    135. message = "您没有权限操作!";
    136. break;
    137. case 404:
    138. message = `请求地址出错: ${error.response.config.url}`;
    139. break;
    140. case 408:
    141. message = "请求超时!";
    142. break;
    143. case 409:
    144. message = "系统已存在相同数据!";
    145. break;
    146. case 500:
    147. message = "服务器内部错误!";
    148. break;
    149. case 501:
    150. message = "服务未实现!";
    151. break;
    152. case 502:
    153. message = "网关错误!";
    154. break;
    155. case 503:
    156. message = "服务不可用!";
    157. break;
    158. case 504:
    159. message = "服务暂时无法访问,请稍后再试!";
    160. break;
    161. case 505:
    162. message = "HTTP 版本不受支持!";
    163. break;
    164. default:
    165. message = "异常问题,请联系管理员!";
    166. break;
    167. }
    168. }
    169. return Promise.reject(message);
    170. }
    171. );
    172. console.log(serviceAxios)
    173. export default serviceAxios; //导出实例

    config/index.js代码如下:

    1. const serverConfig = {
    2. baseURL: 'url', // 请求基础地址,可根据环境自定义
    3. useTokenAuthorization: true, // 是否开启 token 认证
    4. }
    5. export default serverConfig

    api/user.js

    1. import serviceAxios from "../index";
    2. const login = (data) => {
    3. return serviceAxios({
    4. url: "/app/login",
    5. method: "post",
    6. data,
    7. });
    8. }
    9. const getUserInfo = (params) => {
    10. return serviceAxios({
    11. url: "/app/getSystemName",
    12. method: "get",
    13. params,
    14. });
    15. }
    16. export {
    17. login,
    18. getUserInfo
    19. }

    vue文件中使用:

    1. mounted() {
    2. this.init();
    3. this.getInfo();
    4. },
    5. methods: {
    6. async init() {
    7. let params = {
    8. nickName: "admin",
    9. password: "6SJ2Lmmt0BKKiSWhQipe+Q=="
    10. };
    11. let res = await login(params);
    12. localStorage.setItem("token", JSON.stringify(res.data)); // 存放token
    13. console.log(res.data);
    14. },
    15. getInfo() {
    16. let params = {};
    17. getUserInfo(params).then(res => { // 也可以then的方式链式调用
    18. console.log(res);
    19. })
    20. }
    21. }

    3.总结

    我们在此基础上可以根据业务场景做一些以下扩展建议:

    • 请求拦截里面针对 token 进行处理
    • 响应拦截里面判断 token 是否过期等等
    • 在 config/index.js 里面动态更改 baseURL
    • 在请求拦截里面根据业务场景修改请求头
    • 在拦截里面设置全局请求进度条等等

  • 相关阅读:
    HTML+CSS+JS+Django 实现前后端分离的科学计算器、利率计算器(附全部代码在gitcode链接)
    hdl-graph-slam怎么保存tum格式轨迹
    Spring Boot集成WebSocket以及基本使用
    做短视频素材哪里找?这10个自媒体素材网站分享给你
    boltdb 原理
    SpringCloud微服务(六)——Gateway路由网关
    高考英语3500词
    关于在本地启动跨域非nodejs的前后端分离项目
    【微服务】springboot 整合dubbo3开发rest应用
    设计模式——10. 组合模式
  • 原文地址:https://blog.csdn.net/qq_37550440/article/details/125503068