代码拉取完成,页面将自动刷新
将内容联系实际思考或是创作完成的作品放在这里
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
=====================================================================
阅读后的所思所想,或是创作时的思维点滴在这里展现
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() 取消方法,用于后续的取消动作,所以我们需要对应的存储好这个方法。
window.navigator.onLine 来判断是否断网了。 timeout判断请求超时
=====================================================================
将收集到的资料,或是需要归档的记录放到封存层
// 如下写法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"
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(随时监听文件的变更,自动重启服务)
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()
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/'//代理网址
}
}
})
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
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。