uniapp 设置主备请求地址切换
本文实现了一个带主备切换功能的通用请求工具。核心功能包括:1) 通过fallbackRequest.js提供主备地址自动切换机制,在主地址请求失败2次后自动切换到备用地址;2) 封装了GET/POST请求方法,支持超时设置、请求头配置和统一错误处理;3) 全局挂载请求方法,方便在Vue组件中调用。该方案采用Promise链实现延迟重试和错误处理流程,确保在主地址不可用时的服务可用性,同时提供友好的错误提示。请求配置包括主备地址、请求方法、超时时间等参数,支持自定义headers和重试次数设置。
fallbackRequest.js 文件
// utils/fallbackRequest.js/*** 带主备切换的通用请求函数* @param {Object} options* @param {String} options.mainUrl - 主地址* @param {String} options.backupUrl - 备用地址* @param {String} [options.method='GET'] - 请求方法* @param {Any} [options.data] - 请求数据(POST/PUT)* @param {Object} [options.header] - 自定义 header* @param {Number} [options.timeout=10000] - 超时时间(毫秒)* @param {Number} [options.maxRetries=2] - 主地址最大重试次数* @param {String} [options.errorMessage='服务暂时不可用,请稍后再试'] - 备用失败提示语* @returns {Promise}*/
export function requestWithFallback(options) {const {mainUrl,backupUrl,method = 'GET',data = null,header = {'Content-Type': 'application/json;charset=UTF-8','Authorization': 'Bearer ' + uni.getStorageSync('accessToken')?.accessToken || '','x-acs-dingtalk-access-token': uni.getStorageSync('accessToken')?.accessToken || '',},timeout = 5000,maxRetries = 2,errorMessage = '服务暂时不可用,请稍后再试'} = options;let retryCount = 0;// 递归尝试主地址function tryMain() {return uni.request({url: mainUrl,method,data,header,timeout}).then(res => {if (res.statusCode >= 200 && res.statusCode < 300) {return res; // 成功直接返回} else {console.log('[主地址] HTTP 错误:', mainUrl, res);return Promise.reject(res);}}).catch(err => {retryCount++;console.warn(`[主地址] 第 ${retryCount} 次请求失败`, mainUrl, err);if (retryCount < maxRetries) {// ✅ 用 Promise 链实现延迟重试return new Promise((resolve, reject) => {setTimeout(() => {tryMain().then(resolve).catch(reject);}, 1000);});} else {// ✅ 主地址彻底失败,切换到备用(必须 return tryBackup())console.log('[主备切换] 主地址已失败,尝试备用地址:', backupUrl);return new Promise((resolve, reject) => {setTimeout(() => {tryBackup().then(resolve).catch(reject);}, 1000);});}});}// 尝试备用地址function tryBackup() {return uni.request({url: backupUrl,method,data,header,timeout}).then(res => {if (res.statusCode >= 200 && res.statusCode < 300) {return res; // 成功返回响应} else {return Promise.reject(res);}}).catch(err => {return Promise.reject(err);});}// 统一处理错误:提示用户并拒绝function handleError(error) {uni.showToast({title: errorMessage,icon: 'none',duration: 3000});return Promise.reject(error);}// 开始请求流程return new Promise((resolve, reject) => {tryMain().then(res => resolve(res.data)) // 只返回 data.catch(reject);});
}
requestUrl.js 文件中封装请求
import {requestWithFallback
} from "./fallbackRequest.js";
import environment from './https.js'
// 固定参数
const option = {systemToken: "",userId: "",appType: "",
}// 公告方法
const requestApiPost = (url, params) => {return new Promise((resolve, reject) => {requestWithFallback({mainUrl: `${environment.mainUrl}${url}`,backupUrl: `${environment.backupUrl}${url}`,method: 'POST',data: {notLoad: true,...params,...option},maxRetries: 2,timeout: 5000,errorMessage: '服务暂时不可用,请稍后再试'}).then(res => {resolve(res)}).catch(err => {reject(err);})})
};
const queryString = new URLSearchParams(option).toString();
const requestApiGet = (url, params) => {return new Promise((resolve, reject) => {requestWithFallback({mainUrl: `${environment.mainUrl}${url}?${queryString}&${params ? params :''}`,backupUrl: `${environment.backupUrl}${url}?${queryString}&${params ? params :''}`,method: 'GET',maxRetries: 2,timeout: 5000,errorMessage: '服务暂时不可用,请稍后再试'}).then(res => {resolve(res)}).catch(err => {reject(err);})})
};
export default {requestApiPost,requestApiGet
}
在min.js中全局引入
import requestApi from '@/request/requestUrl'
Vue.prototype.$RequestApi = requestApi;
页面中使用
this.$RequestApi.requestApiPost('接口地址','参数').then(res =>{})