1 Star 0 Fork 0

轻语/vue-aixos

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
ISC

行动笔记:

将内容联系实际思考或是创作完成的作品放在这里

import { merge } from '@/utils/index'
import axios from 'axios';
import QS from 'qs';
import { getTokenAUTH } from '@/utils/auth';
import { ElLoading, ElMessage } from 'element-plus';

const IS_USE_GLOBAL_MOCK = true // 是否全部用mock数据  true是  false否
const MOCK_SERVER_IP = 'http://localhost:8888/api'
// baseURL会给每个接口都加上对应前缀,而项目实际场景中,
// 存在一个前端工程,对应多个服务的场景。需要通过不用的前缀代理到不同的服务,故使用自定义prefixUrl
const DEFAULT_PREFIX_URL = process.env.NODE_ENV == 'development' ? 'http://dev.123dailu.com' : 'http://pro.123dailu.com'
const DEFAULT_AXIOS_CONFIG = {
  withCredentials: true, // 允许把cookie传递到后台
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json; charset=utf-8'
  },
  timeout: 10000,
}

const contentTypes = {
  json: 'application/json; charset=utf-8',
  urlencoded: 'application/x-www-form-urlencoded; charset=utf-8',
  multipart: 'multipart/form-data',
}

const LoadingInstance = {
  _target: null, // 保存Loading实例
  _count: 0
};
const pendingRequestMap = new Map();
const fetch = (url, {
  method = 'get',
  params = {}, // 参数,根据method封装参数形式
  axiosConfig = {}, // 自定义http配置 如responseType、headers
  prefixUrl = '',  // 自定义url前缀
  repeat_request = false, // 允许重复请求
  paramsType = 'json', 
  loading = true,
  loadingOptions = {  // elementUI loading配置
    text: '动静有时,大音希声'
  }
}) => {
  const axiosConfigIn = merge(
    DEFAULT_AXIOS_CONFIG,
    axiosConfig
  )
  const instance = axios.create();
  instance.interceptors.request.use(config => {
    config.headers.tokenId = getTokenAUTH()
    switch (method) {
      case 'get':
        config.params = params
        // 如果要在get请求设置content-Type
        if (axiosConfig?.headers?.contentType) { // 未设置requestData的时候源码会删掉Content-Type的设置,其这么做的原因在于是Get请求本身是不需要Content-Type的。
          config.data = true 
        }
        break;
      case 'post':
        config.headers['Content-Type'] = axiosConfig?.headers?.contentType || contentTypes[paramsType]
        // http://axios-js.com/zh-cn/docs/#%E4%BD%BF%E7%94%A8-application-x-www-form-urlencoded-format
        config.data = paramsType === 'urlencoded' ? QS.stringify(params) : params 
        break;
      default:
        break;
    }
    if (!repeat_request) {
      removePending(config); // 重复请求相关
      addPending(config);
    }
    if (loading) {
      LoadingInstance._count++;
      if(LoadingInstance._count === 1) {
        LoadingInstance._target = ElLoading.service(loadingOptions);
      }
    }
    // 移除起始部分 / 所有请求url走相对路径
    config.url = config.url.replace(/^\//, '')
    return config
  })

  instance.interceptors.response.use(
    res => {
      httpErrorStatusHandle(res)
      !repeat_request && removePending(res.config);
      loading && closeLoading(loading); // 关闭loading
      return Promise.resolve(res);
    },
    error => {
      httpErrorStatusHandle(error)
      error.config && !repeat_request && removePending(error.config);
      loading && closeLoading(loading); // 关闭loading
      return Promise.reject(error); // 错误继续返回给到具体页面
    }
  );
  return instance({
    url: IS_USE_GLOBAL_MOCK ? `${MOCK_SERVER_IP}/${url}` : (`${prefixUrl}` ? `${prefixUrl}/${url}` : `${DEFAULT_PREFIX_URL}/${url}`) ,
    method,
    ...axiosConfigIn
  })
}

/**
 * 处理异常
 * @param {*} error 
 */
const httpErrorStatusHandle = error => {
  let message
  if (error?.response) {
    const msgByCode = new Map([
      [302, '接口重定向'],
      [400, '参数不正确!'],
      [401, '您未登录,或者登录已经超时,请先登录!'], // TODO跳转登录页
      [403, '您没有权限操作!'],
      // [404, `请求地址出错: ${error?.response?.config?.url}`], // 在正确域名下
      [408, '请求超时!'],
      [409, '系统已存在相同数据!'],
      [500, '服务器内部错误!'],
      [501, '服务未实现!'],
      [502, '网关错误!'],
      [503, '服务不可用!'],
      [504, '服务暂时无法访问,请稍后再试!'],
      [505, 'HTTP版本不受支持!']
    ])
    message = msgByCode.get(error?.response?.status) || '异常问题,请联系管理员!'
  }
  if(axios.isCancel(error)) return console.error('请求的重复请求:' + error.message);
  if (error?.message?.includes('timeout')) message = '网络请求超时!';
  if (error?.message?.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!';
  message && 
  ElMessage({
    type: 'error',
    message
  })
}
/**
 * 关闭Loading层实例
 * @param {*} _options 
 */
const closeLoading = (loading) => {
  if(loading && LoadingInstance._count > 0) LoadingInstance._count--;
  if(LoadingInstance._count === 0) {
    LoadingInstance._target.close();
    LoadingInstance._target = null;
  }
}
/**
 * 生成每个请求唯一的键
 * @param {*} config 
 * @returns string
 */
const getPendingKey = (config) => {
  let { url, method, params, data } = config;
  data = typeof data === 'object' ? JSON.stringify(data) : '' + data
  return [url, method, JSON.stringify(params), data].join('&');
}
/**
 * 储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
 * @param {*} config 
 */
const addPending = (config) => {
  const pendingKey = getPendingKey(config);
  console.log(pendingKey, 'pendingKey')
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequestMap.has(pendingKey)) {
      pendingRequestMap.set(pendingKey, cancel);
    }
  });
}
/**
 * 删除重复的请求
 * @param {*} config 
 */
const removePending = (config) => {
  const pendingKey = getPendingKey(config);
  if (pendingRequestMap.has(pendingKey)) {
     const cancelToken = pendingRequestMap.get(pendingKey);
     cancelToken(pendingKey);
     pendingRequestMap.delete(pendingKey);
  }
}


export const get = (url, arg) => fetch(url, { ...arg, method: 'get' })
export const post = (url, arg) => fetch(url, { ...arg, method: 'post' })

附录

地址:vue-axios

cd vue-axios/service   // 开启本地服务器
nodemon app.js

cd vue-axios  
npm i & npm run dev

=====================================================================

构思笔记:

阅读后的所思所想,或是创作时的思维点滴在这里展现

  • prefixUrl
  • 支持get请求添加content-type
  • 支持loading配置
  • 支持异常状态提示
  • 支持取消重复请求
  • 支持post请求
  • Content-Type: application/json

    * Content-Type: application/x-www-form-urlencoded
    * Content-Type: multipart/form-data
    

取消请求

场景:频繁触发。 其实取消后的请求还是有可能会到达了后端,只是前端浏览器不处理而已。 优化手段可以在源头阶段比如防抖节流之类。 故axios重复请求取消作为兜底手段。 思路:* 地址、参数、方法一致则视为统一请求。将首次请求其维护在map中,第二次请求时先在map中判断是否任务已在队列中。 取消底层借助axios的cancelToken(底层还是xml的abort)。 new axios.CancelToken()给每个请求带上一个专属的CancelToken,之后会接收到一个cancel() 取消方法,用于后续的取消动作,所以我们需要对应的存储好这个方法。

Loading

  • 同一时间内发起多个请求,我们只需要展示一个Loading层即可,不需要产生多个造成重复展示。
  • 同一时间内发起多个请求展示的Loading层以最后一个请求响应而关闭销毁。
  • 支持element原生配置

状态码解释

window.navigator.onLine 来判断是否断网了。 timeout判断请求超时 ​

===================================================================== ​

封存笔记:

将收集到的资料,或是需要归档的记录放到封存层

  • get参数为params: {params: {}}, post为data。
  • 当content-type为application/x-www-form-urlencoded时,需要对参数进行序列化qs.stringify()或借用new URLSearchParams();
  • transformRequest 就是允许在向服务器发送前,修改请求数据,但只能用在 'PUT','POST' 和 'PATCH' 这几个请求方法,且后面数组中的函数必须返回一个字符串,或 ArrayBuffer,
  • Content-Type(内容类型):一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP 网页点击的结果却是下载一个文件或一张图片的原因。告诉客户端实际返回的内容的内容类型。
  • get请求设置content-type时,需要为data赋值。 源码中会检索,若为false,则移除content-type。
  • 当使用export default导出时,import不能用解构赋值,原因在于 import 语句中的"解构赋值"并不是解构赋值,而是 named imports,语法上和解构赋值很像,但还是有所差别。
// 如下写法babel 6之前允许,babel 6之后就不能了。
// a.js
import { foo, bar } from "./b"
// b.js
export default {
  foo: "foo",
  bar: "bar"
}


export default {   // 当用webpack构建后会变成类似如下
  host: 'localhost',
  port: 80
}

module.exports.default = {
  host: 'localhost',
  port: 80
}
因此只能改成
// 方案1
import b from './b'
let { foo, bar } = b

// 方案2
// a.js
import { foo, bar } from "./b"
// b.js
let foo =  "foo"
let bar = "bar"
export { foo, bar }

// 方案3
// a.js
import { foo, bar } from "./b"
// b.js
export let foo =  "foo"
export let bar = "bar"
  • node进程守护5种方法
  1. forever
npm install forever -g   #安装
forever start app.js     #启动应用
forever stop app.js      #关闭应用
forever restart app.js   #重启应用
forever stopall          #关闭所有应用
forever restartall       #重启所有应用
forever list             #显示所有运行的应用
2. [PM2](http://pm2.keymetrics.io/)
npm install pm2 -g #安装
pm2 start app.js #启动
pm2 list    #查看所有运行中的应用
pm2 stop    #关闭
pm2 restart #重启
pm2 delete  #删除
3. [StrongLoop-PM](http://strong-pm.io)

4. [Supervisor](https://github.com/Supervisor/supervisor)
5. nohup
6. nodemon(随时监听文件的变更,自动重启服务)

vue3

  • vue.prototype.$http方式替换为globalProperties
import { createApp } from 'vue'
import App from './App.vue'
import {
  get,
  post,
} from '@/api/fetch'

const app = createApp(App)
app.config.globalProperties.$http = {
  get,
  post,
}

app.mount('#app')
// app.vue
const { appContext : { config: { globalProperties } } } = getCurrentInstance()
getCurrentInstance.$http.post()
  • vite配置alias和proxy
import {
  defineConfig
 } from 'vite'
 import path from "path";
 import vue from '@vitejs/plugin-vue'

 export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src")
    },
  },
   plugins: [vue()],
   server: {
     proxy: {
      '/api': 'http://localhost:8888/', //代理网址
      '/api2': 'http://localhost:8888/'//代理网址
    }
  }
 })
 
  • require.context替换为import.meta.globEager
const files = import.meta.globEager('./main/*.js')
const modules = {}
for (const item in files) { 
  if (Object.prototype.hasOwnProperty.call(files, item)) {
    const key = (item.replace(/(\.\/|\.js)/g, '')).split('/').slice(-1)[0]
    modules[key] = files[item].default 
  }
}
console.log(modules, 'modules')

export default modules

ISC License Copyright (c) 2021, 轻语 Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

简介

暂无描述 展开 收起
README
ISC
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/yunbooks/vue-aixos.git
git@gitee.com:yunbooks/vue-aixos.git
yunbooks
vue-aixos
vue-aixos
develop

搜索帮助