wordpress中文版和英文版,上海做网站优化的公司,移动端有哪些,请人做网站卖东西好吗在 Vue 项目中#xff0c;封装 Axios 并实现加密、重复请求优化、请求取消、页面切换时取消未完成的请求、以及区分上传和下载操作是非常常见的需求。下面将逐一讲解这些需求的实现方式。
1. Axios 的基本封装
首先#xff0c;我们可以将 Axios 封装到一个服务层中#xf…在 Vue 项目中封装 Axios 并实现加密、重复请求优化、请求取消、页面切换时取消未完成的请求、以及区分上传和下载操作是非常常见的需求。下面将逐一讲解这些需求的实现方式。
1. Axios 的基本封装
首先我们可以将 Axios 封装到一个服务层中方便统一管理请求和拦截。
// src/utils/request.js
import axios from axios;
import { encryptRequestData, decryptResponseData } from ./crypto; // 假设有加密解密工具
import { ElMessage } from element-plus; // UI 组件库的消息提示// 创建 axios 实例
const service axios.create({baseURL: process.env.VUE_APP_BASE_API, // api base_urltimeout: 5000, // 请求超时时间
});// 请求拦截器
service.interceptors.request.use((config) {// 请求加密if (config.data) {config.data encryptRequestData(config.data); // 数据加密}// token 放入 header 以防用户身份验证const token localStorage.getItem(token);if (token) {config.headers[Authorization] Bearer ${token};}return config;},(error) {return Promise.reject(error);}
);// 响应拦截器
service.interceptors.response.use((response) {// 响应解密if (response.data) {response.data decryptResponseData(response.data); // 数据解密}return response;},(error) {ElMessage.error(请求失败);return Promise.reject(error);}
);export default service;2. 前后端加密的使用
前后端的加密一般是基于某种加密算法例如 AES 或 RSA。这里假设你有现成的加密和解密工具可以在请求拦截器中对请求进行加密在响应拦截器中对响应进行解密。
加密请求数据通过加密函数处理传输给后端的就是密文。解密响应数据通过解密函数还原为可读内容。
// utils/crypto.js
import CryptoJS from crypto-js;// 加密函数
export function encryptRequestData(data) {const key CryptoJS.enc.Utf8.parse(16characterskey); // 密钥const iv CryptoJS.enc.Utf8.parse(16charactersiv ); // 偏移量const encrypted CryptoJS.AES.encrypt(JSON.stringify(data), key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();
}// 解密函数
export function decryptResponseData(ciphertext) {const key CryptoJS.enc.Utf8.parse(16characterskey); // 密钥const iv CryptoJS.enc.Utf8.parse(16charactersiv ); // 偏移量const bytes CryptoJS.AES.decrypt(ciphertext, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});const decryptedData bytes.toString(CryptoJS.enc.Utf8);return JSON.parse(decryptedData);
}3. 重复请求的优化
为避免同一请求短时间内被多次发送可以通过 axios 的请求拦截器实现防重复请求的功能。可以使用一个 Map 来存储每个请求的唯一标识当同一请求发送时进行检查防止重复发送。
const pendingRequests new Map();const getRequestKey (config) {const { method, url, params, data } config;return [method, url, JSON.stringify(params), JSON.stringify(data)].join();
};// 添加请求拦截器
service.interceptors.request.use((config) {const requestKey getRequestKey(config);if (pendingRequests.has(requestKey)) {config.cancelToken new axios.CancelToken((cancel) {cancel(Duplicate request: ${requestKey});});} else {pendingRequests.set(requestKey, config);}return config;},(error) {return Promise.reject(error);}
);// 添加响应拦截器
service.interceptors.response.use((response) {const requestKey getRequestKey(response.config);pendingRequests.delete(requestKey); // 移除完成的请求return response;},(error) {if (axios.isCancel(error)) {console.warn(error.message); // 重复请求被取消} else {// 其他错误处理}return Promise.reject(error);}
);4. 单个请求的取消控制
对于单个请求你可以使用 axios.CancelToken 来控制某个请求的取消。
const source axios.CancelToken.source();// 发起请求时传入取消 token
service({url: /some-endpoint,method: get,cancelToken: source.token
}).then((response) {console.log(请求成功, response);}).catch((error) {if (axios.isCancel(error)) {console.log(请求被取消, error.message);}});// 在需要的时候取消请求
source.cancel(取消请求);5. 页面切换时取消未完成的请求
可以在 Vue 路由的 beforeRouteLeave 钩子中控制页面切换时取消未完成的请求。
export default {data() {return {requestSource: null, // 存储取消 token};},methods: {fetchData() {this.requestSource axios.CancelToken.source();service.get(/api/data, { cancelToken: this.requestSource.token }).then(response {console.log(请求成功, response);}).catch(error {if (axios.isCancel(error)) {console.log(请求被取消);} else {console.error(请求错误, error);}});}},beforeRouteLeave(to, from, next) {if (this.requestSource) {this.requestSource.cancel(页面切换取消请求);}next();}
};6. 区分上传和下载的使用
上传文件通常通过 FormData 来上传文件并在 onUploadProgress 中监控上传进度。
let formData new FormData();
formData.append(file, file);service.post(/upload, formData, {headers: {Content-Type: multipart/form-data},onUploadProgress: (progressEvent) {let progress (progressEvent.loaded / progressEvent.total) * 100;console.log(上传进度: ${progress}%);}
});下载文件下载文件时可以指定 responseType 为 blob并处理文件保存。
service.get(/download, {responseType: blob,onDownloadProgress: (progressEvent) {let progress (progressEvent.loaded / progressEvent.total) * 100;console.log(下载进度: ${progress}%);}
}).then(response {const url window.URL.createObjectURL(new Blob([response.data]));const link document.createElement(a);link.href url;link.setAttribute(download, file.pdf); // 下载文件名document.body.appendChild(link);link.click();
});总结
Axios 的封装统一管理请求和拦截。使用加密、解密函数对请求和响应数据进行保护。防止重复请求通过 requestKey 唯一标识每个请求。提供单个请求取消和页面切换时取消未完成请求的机制。针对上传、下载分别进行处理监听进度。
根据这些实现你可以根据需求进一步调整封装的细节和功能。
可以结合 vue-router 的导航守卫使用尤其是在页面切换时取消未完成的请求。通过在 vue-router 的钩子函数例如 beforeRouteLeave 或 beforeEach中调用 axios 的取消方法可以确保在用户切换页面时及时取消正在进行的请求避免无效请求消耗资源。
实现步骤 创建一个全局的取消请求管理工具使用一个 Map 来存储每个页面的取消请求函数CancelToken当页面切换时从 Map 中找到对应的取消方法并执行。 在路由守卫中调用取消方法在 beforeEach 或 beforeRouteLeave 钩子中调用取消请求的逻辑确保切换路由时清理未完成的请求。
具体实现方案
1. 取消请求的封装
我们可以在 axios 的封装文件中为每个请求生成一个取消令牌CancelToken并将其存储在全局的 cancelMap 中。
// src/utils/request.js
import axios from axios;const cancelMap new Map(); // 全局的取消请求管理工具const service axios.create({baseURL: process.env.VUE_APP_BASE_API, // API 基础路径timeout: 10000, // 超时时间
});// 请求拦截器
service.interceptors.request.use((config) {const source axios.CancelToken.source(); // 创建一个取消令牌config.cancelToken source.token; // 将取消令牌附加到请求中// 使用唯一的标识例如URL请求方式来存储取消令牌const requestKey ${config.url}${config.method};cancelMap.set(requestKey, source.cancel); // 存储取消请求函数return config;},(error) {return Promise.reject(error);}
);// 响应拦截器
service.interceptors.response.use((response) {// 请求成功后删除对应的取消函数const requestKey ${response.config.url}${response.config.method};cancelMap.delete(requestKey);return response;},(error) {// 如果请求被取消不做其他处理if (axios.isCancel(error)) {console.log(请求被取消);}return Promise.reject(error);}
);// 取消未完成的请求
export function cancelPendingRequests() {cancelMap.forEach((cancel) {cancel(路由切换取消请求); // 执行取消函数});cancelMap.clear(); // 清空取消函数
}export default service;2. 在 vue-router 中使用取消逻辑
接下来我们在 vue-router 中添加导航守卫确保在每次路由切换时都调用 cancelPendingRequests 来取消未完成的请求。
// src/router/index.js
import { createRouter, createWebHistory } from vue-router;
import { cancelPendingRequests } from /utils/request; // 引入取消请求方法
import Home from /views/Home.vue;
import About from /views/About.vue;const routes [{path: /,name: Home,component: Home,},{path: /about,name: About,component: About,},
];const router createRouter({history: createWebHistory(process.env.BASE_URL),routes,
});// 全局路由守卫 - 在每次路由切换前取消未完成的请求
router.beforeEach((to, from, next) {cancelPendingRequests(); // 取消未完成的请求next(); // 继续路由切换
});export default router;3. 在组件中发起请求
在组件中正常发起 axios 请求不需要额外的处理。每次请求都会通过 axios 封装自动附加 CancelToken并在路由切换时通过 cancelPendingRequests 自动取消。
// src/views/Home.vue
templatedivh1Home/h1p{{ data }}/p/div
/templatescript
import service from /utils/request;export default {data() {return {data: null,};},mounted() {this.fetchData();},methods: {async fetchData() {try {const response await service.get(/api/home);this.data response.data;} catch (error) {console.error(error);}},},
};
/script4. 页面级取消请求
有时我们只需要在页面组件内部取消请求比如当用户离开页面时取消当前页面的请求这时可以使用组件的 beforeRouteLeave 钩子。
// src/views/About.vue
templatedivh1About/h1p{{ data }}/p/div
/templatescript
import service from /utils/request;
import { ref } from vue;export default {setup() {const data ref(null);let requestSource null;const fetchData async () {requestSource service.CancelToken.source();try {const response await service.get(/api/about, {cancelToken: requestSource.token,});data.value response.data;} catch (error) {if (axios.isCancel(error)) {console.log(请求被取消);} else {console.error(error);}}};return { data, fetchData };},mounted() {this.fetchData();},beforeRouteLeave(to, from, next) {if (this.requestSource) {this.requestSource.cancel(页面离开取消请求);}next();},
};
/script总结
全局取消通过在 vue-router 的 beforeEach 守卫中调用 cancelPendingRequests每次路由切换时都会取消未完成的请求避免页面切换后无用的网络请求消耗。局部取消在页面组件内部使用 beforeRouteLeave 钩子取消单个页面的请求确保当用户离开页面时及时中止未完成的请求。防止重复请求通过对请求进行唯一标识并在发起请求前检查是否有相同请求正在进行可以防止重复发送相同的请求。
通过结合 vue-router 和 axios 的 CancelToken可以有效地管理请求的生命周期确保用户体验的流畅性。
在实际开发中前端项目可能会需要请求不同的服务地址例如不同的 API 网关、微服务等而 Axios 的 baseURL 是请求的默认根路径。如果项目中需要根据具体请求来动态配置不同的 baseURL有几种方式可以处理
常见解决方案
1. 在请求时动态指定 baseURL
可以根据不同的业务逻辑或接口动态为每个请求指定 baseURL。Axios 支持在发起请求时覆盖默认的 baseURL通过为每个请求单独设置 baseURL 来实现多服务地址请求。
import axios from axios;// 默认 axios 实例
const service axios.create({baseURL: process.env.VUE_APP_BASE_API, // 默认的 baseURLtimeout: 10000, // 超时时间
});// 示例根据业务逻辑或特定条件指定不同的 baseURL
export function fetchDataFromServiceA() {return service({url: /serviceA/data,baseURL: https://api.serviceA.com, // 为这个请求动态设置 baseURLmethod: get,});
}export function fetchDataFromServiceB() {return service({url: /serviceB/data,baseURL: https://api.serviceB.com, // 另一个服务的 baseURLmethod: get,});
}2. 创建多个 Axios 实例
如果不同服务的 baseURL 是固定的并且它们各自有独立的配置那么可以为每个服务创建一个独立的 Axios 实例。这样可以对不同服务有不同的 baseURL、headers 或其他配置。
import axios from axios;// 服务A的 axios 实例
const serviceA axios.create({baseURL: https://api.serviceA.com,timeout: 10000,
});// 服务B的 axios 实例
const serviceB axios.create({baseURL: https://api.serviceB.com,timeout: 10000,
});// 使用 serviceA 发送请求
export function fetchServiceAData() {return serviceA.get(/data);
}// 使用 serviceB 发送请求
export function fetchServiceBData() {return serviceB.get(/data);
}这种方式使得各个服务的配置更加独立清晰有助于代码的可维护性。
3. 根据环境动态配置 baseURL
对于一些需要根据不同的环境如开发、生产等动态切换服务地址的需求可以在配置文件中根据 NODE_ENV 来设定不同的 baseURL。
// .env.development
VUE_APP_BASE_APIhttps://dev.api.com// .env.production
VUE_APP_BASE_APIhttps://prod.api.com在 axios 的封装文件中读取环境变量
import axios from axios;const service axios.create({baseURL: process.env.VUE_APP_BASE_API, // 根据环境变量设置 baseURLtimeout: 10000,
});export default service;4. 通过请求拦截器动态修改 baseURL
如果需要根据请求的特定条件例如请求的路径、参数等来动态设置不同的 baseURL可以在 axios 的请求拦截器中根据条件修改 config.baseURL。
import axios from axios;// 默认 axios 实例
const service axios.create({baseURL: process.env.VUE_APP_BASE_API, // 默认的 baseURLtimeout: 10000,
});// 请求拦截器 - 根据特定条件动态设置 baseURL
service.interceptors.request.use((config) {if (config.url.includes(/serviceA)) {config.baseURL https://api.serviceA.com; // 动态切换到 serviceA 的 baseURL} else if (config.url.includes(/serviceB)) {config.baseURL https://api.serviceB.com; // 动态切换到 serviceB 的 baseURL}return config;},(error) {return Promise.reject(error);}
);export default service;5. 在组件中指定 baseURL
在组件中直接为特定的请求指定 baseURL这也是一种灵活的方式适用于只在特定组件内进行请求的情况。
templatedivbutton clickfetchData获取数据/button/div
/templatescript
import axios from axios;export default {methods: {fetchData() {axios({url: /data,baseURL: https://api.serviceA.com, // 在组件中指定 baseURLmethod: get,}).then((response) {console.log(数据:, response.data);}).catch((error) {console.error(请求错误:, error);});},},
};
/script6. 根据 API 名称或者模块切换 baseURL
可以将 API 分模块管理通过模块名自动选择对应的 baseURL。例如可以根据模块名动态选择不同的 baseURL。
const serviceMap {serviceA: https://api.serviceA.com,serviceB: https://api.serviceB.com,
};export function request({ module, url, ...options }) {const service axios.create({baseURL: serviceMap[module], // 动态选择 baseURLtimeout: 10000,});return service({ url, ...options });
}// 使用
request({module: serviceA,url: /data,method: get,
}).then(response {console.log(response.data);
});总结
动态设置 baseURL直接在请求中指定 baseURL适用于小范围的不同服务地址请求。多个 Axios 实例为每个服务创建独立的 Axios 实例适用于多个不同服务地址的项目清晰明确。环境变量切换根据开发、生产环境自动配置不同的 baseURL。拦截器动态修改通过请求拦截器动态修改 baseURL适合复杂场景的需求。模块化管理根据模块名或者业务需求选择不同的 baseURL可读性更高。
根据你的项目规模和需求可以选择最适合的方式处理多 baseURL 问题。
加密解密方案
在前后端通信中使用加密方案来保护数据的安全性是非常重要的。常见的加密方式通常有对称加密、非对称加密和哈希算法。以下是一些在 Axios 中常用的加密方案结合前后端的使用场景以及如何在 Axios 请求中应用这些加密方式。
常见加密方式
1. 对称加密Symmetric Encryption
对称加密是指加密和解密使用相同的密钥。常见的对称加密算法有 AESAdvanced Encryption Standard。在前后端通信中可以使用对称加密对敏感信息进行加密后端使用相同的密钥解密。
使用场景
对称加密通常用于加密敏感数据如用户密码、银行信息等在传输中的保护。
在 Axios 中使用 AES 加密
npm install crypto-jsimport axios from axios;
import CryptoJS from crypto-js;const secretKey your-secret-key; // 需要和后端保持一致的密钥// 加密函数
function encryptData(data) {const ciphertext CryptoJS.AES.encrypt(JSON.stringify(data), secretKey).toString();return ciphertext;
}// 解密函数在后端实现前端不需要
function decryptData(ciphertext) {const bytes CryptoJS.AES.decrypt(ciphertext, secretKey);const decryptedData JSON.parse(bytes.toString(CryptoJS.enc.Utf8));return decryptedData;
}// 使用加密后的数据发送请求
axios.post(/api/encrypt, {data: encryptData({username: user1,password: mypassword,}),
}).then(response {console.log(Response:, response.data);
}).catch(error {console.error(Error:, error);
});在这种情况下前端对敏感数据进行 AES 加密然后通过 Axios 发送给服务器服务器在收到数据后用相同的密钥进行解密。
2. 非对称加密Asymmetric Encryption
非对称加密使用一对密钥公钥和私钥。常见的非对称加密算法是 RSA。通常前端使用公钥加密数据后端使用私钥解密数据。非对称加密适用于加密少量数据因为它的加密速度较慢。
使用场景
非对称加密常用于需要高度安全性的数据传输如敏感的身份验证信息、密钥交换等。
在 Axios 中使用 RSA 加密
npm install node-forgeimport axios from axios;
import forge from node-forge;// 从后端获取公钥
axios.get(/api/public-key).then(response {const publicKey response.data.publicKey;// 使用 RSA 公钥加密const encryptWithRSA (data, publicKey) {const rsa forge.pki.publicKeyFromPem(publicKey);const encrypted rsa.encrypt(forge.util.encodeUtf8(data));return forge.util.encode64(encrypted);};// 加密数据const encryptedData encryptWithRSA(JSON.stringify({username: user1,password: mypassword,}), publicKey);// 发送加密后的数据axios.post(/api/encrypt, {data: encryptedData,}).then(response {console.log(Response:, response.data);});
});在这种场景下前端获取后端的公钥后用 RSA 加密敏感数据发送给服务器。后端用私钥解密数据。
3. 哈希算法Hashing
哈希算法用于将任意长度的数据映射为固定长度的散列值。常见的哈希算法包括 MD5、SHA-256 等。哈希算法通常用于验证数据的完整性例如校验文件是否被篡改或传输过程中是否损坏。
使用场景
哈希函数常用于密码的加盐哈希存储或通过签名验证请求的完整性如 HMAC。
在 Axios 中使用 SHA-256 进行数据签名
npm install crypto-jsimport axios from axios;
import CryptoJS from crypto-js;// 加盐哈希
function hashData(data, secret) {const hash CryptoJS.HmacSHA256(data, secret);return hash.toString(CryptoJS.enc.Hex);
}// 创建要发送的数据
const data JSON.stringify({username: user1,password: mypassword,
});// 生成签名
const secret your-secret-key;
const signature hashData(data, secret);// 发送带有签名的请求
axios.post(/api/verify, {data,signature, // 传递签名以验证完整性
}).then(response {console.log(Response:, response.data);
});这种方式确保请求在传输过程中没有被篡改后端可以使用相同的密钥对接收到的数据进行哈希计算并验证签名是否匹配。
4. 混合加密
混合加密是对称加密和非对称加密的结合通常用于提高安全性和效率。在实际应用中通常会使用 RSA 非对称加密来加密 AES 对称加密的密钥而数据则使用 AES 加密这样可以兼顾效率和安全性。
使用场景
混合加密常用于需要传输大量数据但仍需要高度安全性的场景特别是前端生成随机的对称密钥用 RSA 加密这个密钥后传递给后端。
实现混合加密
import axios from axios;
import CryptoJS from crypto-js;
import forge from node-forge;// 使用 AES 生成随机密钥
function generateAESKey() {return CryptoJS.lib.WordArray.random(16).toString();
}// AES 加密数据
function encryptData(data, aesKey) {return CryptoJS.AES.encrypt(data, aesKey).toString();
}// RSA 公钥加密 AES 密钥
function encryptAESKeyWithRSA(aesKey, publicKey) {const rsa forge.pki.publicKeyFromPem(publicKey);const encrypted rsa.encrypt(forge.util.encodeUtf8(aesKey));return forge.util.encode64(encrypted);
}// 混合加密过程
axios.get(/api/public-key).then(response {const publicKey response.data.publicKey;const aesKey generateAESKey();const encryptedData encryptData(JSON.stringify({username: user1,password: mypassword,}), aesKey);const encryptedAESKey encryptAESKeyWithRSA(aesKey, publicKey);// 发送加密的数据和加密的 AES 密钥axios.post(/api/encrypt, {encryptedData,encryptedAESKey,}).then(response {console.log(Response:, response.data);});
});在这种情况下前端使用 AES 加密实际数据并使用 RSA 加密 AES 密钥。后端接收到加密的密钥和数据后先用 RSA 私钥解密 AES 密钥再用 AES 密钥解密数据。
重复请求的优化和请求取消 防止重复请求 通过使用请求的唯一标识例如 url method来管理请求防止用户短时间内重复发送相同请求。可以在发送请求前检查是否有相同的请求正在进行如果有则不发送新的请求。 取消请求 可以结合 axios 的 CancelToken在用户离开页面或切换操作时取消未完成的请求避免浪费资源。
总结
对称加密如 AES适用于加密传输的敏感数据。非对称加密如 RSA适用于密钥交换和少量敏感数据的加密。哈希算法如 SHA-256常用于数据完整性验证。混合加密结合 AES 和 RSA兼顾性能和安全性常用于大数据加密。
通过这些加密方案能够有效地保护前后端通信中的数据安全。