关注大师不迷路,大师带你上高度~
文章目录
前言
关注大师不迷路,大师带你上高度~
在使用 uni-app 开发跨平台应用时,封装 request 请求是非常常见且重要的工作。良好的封装可以提高代码复用性、简化错误处理、提升用户体验。下面是一个完整的 uni-app 中 request 请求封装的实现,包括了基础的网络请求封装、请求拦截、响应拦截、错误处理、以及请求重试等功能。
一、request请求是什么?
request 是一种常见的网络请求方式,在 uni-app 或者任何前端框架中,通常用来与服务器进行数据交换,发送 HTTP 请求并获取响应数据。它是客户端和服务器之间进行通信的一种标准方式,能够实现如获取数据、提交表单、上传文件等操作。
在 uni-app 中,uni.request 是官方提供的用于发送网络请求的 API。它是一个基于 Promise 的封装,支持各种 HTTP 请求方法(如 GET、POST、PUT、DELETE 等),并且能够进行跨平台支持(支持 iOS、Android、H5、微信小程序等平台)。
二、使用步骤
一、基本封装
首先,我们需要创建一个请求封装函数,封装网络请求。可以根据需求封装 GET、POST 等常用请求方法。我们会用 uni.request 来进行实际的网络请求。
创建请求封装模块
在 src/utils 目录下创建 request.js 文件(如果没有 utils 目录可以自行创建)。
// src/utils/request.js
// 请求基础配置
const BASE_URL = 'https://api.example.com'; // 基础 API URL
const TIMEOUT = 10000; // 请求超时时间,单位毫秒
// 请求头
const HEADER = {
'Content-Type': 'application/json', // 默认 JSON 请求
// 可以加入 token 或者其他自定义头部
};
// 默认请求方法(可以根据需求扩展 POST、PUT、DELETE 等)
const request = (options) => {
const { url, method = 'GET', data = {}, headers = {} } = options;
return new Promise((resolve, reject) => {
// 配置请求参数
uni.request({
url: BASE_URL + url, // 基础地址 + 请求路径
method,
data,
header: { ...HEADER, ...headers }, // 合并请求头
timeout: TIMEOUT, // 设置超时
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data); // 请求成功,返回数据
} else {
reject(res); // 请求失败,返回错误信息
}
},
fail: (err) => {
reject(err); // 网络失败,返回错误信息
},
});
});
};
export default {
request,
};
二、请求拦截和响应拦截
为了更好地处理每个请求的过程,我们可以实现请求拦截和响应拦截。比如在请求之前给请求加上 token,在响应后统一处理错误提示等。
请求拦截器
我们可以使用 uni.request 的前置处理(拦截器)来实现一些操作,比如在请求头中自动加上 token,或者根据用户的权限进行一些验证等。
// 在 request.js 中添加请求拦截器
let requestQueue = [];
const setRequestHeaders = () => {
// 假设我们从缓存中获取 token
const token = uni.getStorageSync('token');
if (token) {
return { Authorization: `Bearer ${token}` };
}
return {};
};
const requestInterceptor = () => {
uni.addInterceptor('request', {
invoke(options) {
// 这里可以添加请求的前置处理
options.header = {
...options.header,
...setRequestHeaders(),
};
requestQueue.push(options);
return options;
},
success(res) {
return res;
},
fail(err) {
return err;
},
});
};
// 调用请求拦截器
requestInterceptor();
响应拦截器
在响应拦截器中,我们可以统一处理请求成功或失败的响应,做一些通用的逻辑处理,比如全局的错误提示、Token 过期的处理等。
const responseInterceptor = () => {
uni.addInterceptor('request', {
success(res) {
// 响应成功
if (res.statusCode === 200) {
// 可以在这里统一处理返回的数据
return res.data;
} else {
// 统一处理错误
handleError(res);
return Promise.reject(res);
}
},
fail(err) {
// 请求失败
uni.showToast({
title: '网络请求失败',
icon: 'none',
});
return Promise.reject(err);
},
});
};
// 错误处理函数
const handleError = (res) => {
// 例如:Token 过期的处理
if (res.statusCode === 401) {
uni.showToast({
title: '身份验证过期,请重新登录',
icon: 'none',
});
// 清除用户登录信息,并跳转到登录页
uni.removeStorageSync('token');
uni.redirectTo({
url: '/pages/login/login',
});
} else {
uni.showToast({
title: res.data.message || '请求失败',
icon: 'none',
});
}
};
// 调用响应拦截器
responseInterceptor();
三、封装不同类型的请求方法
我们可以根据不同的请求类型封装 GET、POST、PUT、DELETE 等方法,提供更简洁的 API 使用。
const get = (url, data = {}, headers = {}) => {
return request({
url,
method: 'GET',
data,
headers,
});
};
const post = (url, data = {}, headers = {}) => {
return request({
url,
method: 'POST',
data,
headers,
});
};
const put = (url, data = {}, headers = {}) => {
return request({
url,
method: 'PUT',
data,
headers,
});
};
const del = (url, data = {}, headers = {}) => {
return request({
url,
method: 'DELETE',
data,
headers,
});
};
export default {
get,
post,
put,
del,
};
四、请求重试(可选)
为了提高应用的稳定性,我们还可以为请求添加重试机制,特别是在网络请求失败时进行自动重试。
const retryRequest = (options, retries = 3) => {
return new Promise((resolve, reject) => {
const attempt = (attemptsLeft) => {
request(options)
.then(resolve)
.catch((err) => {
if (attemptsLeft > 0) {
console.log(`请求失败,重试中... 剩余重试次数: ${attemptsLeft}`);
attempt(attemptsLeft - 1); // 重试请求
} else {
reject(err); // 达到最大重试次数,返回错误
}
});
};
attempt(retries); // 发起第一次请求
});
};
你可以将这个 retryRequest 方法结合现有的请求方法,例如:
const getWithRetry = (url, data = {}, headers = {}, retries = 3) => {
return retryRequest({ url, method: 'GET', data, headers }, retries);
};
五、最终代码
request.js
// src/utils/request.js
// 请求基础配置
const BASE_URL = 'https://api.example.com'; // 基础 API URL
const TIMEOUT = 10000; // 请求超时时间,单位毫秒
// 默认请求头
const HEADER = {
'Content-Type': 'application/json', // 默认 JSON 请求
};
// 请求队列,用于拦截器
let requestQueue = [];
// 设置请求头
const setRequestHeaders = () => {
const token = uni.getStorageSync('token');
if (token) {
return { Authorization: `Bearer ${token}` };
}
return {};
};
// 请求拦截器
const requestInterceptor = () => {
uni.addInterceptor('request', {
invoke(options) {
options.header = {
...options.header,
...setRequestHeaders(),
};
requestQueue.push(options);
return options;
},
success(res) {
return res;
},
fail(err) {
return err;
},
});
};
// 响应拦截器
const responseInterceptor = () => {
uni.addInterceptor('request', {
success(res) {
if (res.statusCode === 200) {
return res.data;
} else {
handleError(res);
return Promise.reject(res);
}
},
fail(err) {
uni.showToast({
title: '网络请求失败',
icon: 'none',
});
return Promise.reject(err);
},
});
};
// 错误处理函数
const handleError = (res) => {
if (res.statusCode === 401) {
uni.showToast({
title: '身份验证过期,请重新登录',
icon: 'none',
});
uni.removeStorageSync('token');
uni.redirectTo({
url: '/pages/login/login',
});
} else {
uni.showToast({
title: res.data.message || '请求失败',
icon: 'none',
});
}
};
// 封装网络请求
const request = (options) => {
const { url, method = 'GET', data = {}, headers = {} } = options;
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + url, // 基础地址 + 请求路径
method,
data,
header: { ...HEADER, ...headers }, // 合并请求头
timeout: TIMEOUT, // 设置超时
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data); // 请求成功,返回数据
} else {
reject(res); // 请求失败,返回错误信息
}
},
fail: (err) => {
reject(err); // 网络失败,返回错误信息
},
});
});
};
// 请求重试机制
const retryRequest = (options, retries = 3) => {
return new Promise((resolve, reject) => {
const attempt = (attemptsLeft) => {
request(options)
.then(resolve)
.catch((err) => {
if (attemptsLeft > 0) {
console.log(`请求失败,重试中... 剩余重试次数: ${attemptsLeft}`);
attempt(attemptsLeft - 1); // 重试请求
} else {
reject(err); // 达到最大重试次数,返回错误
}
});
};
attempt(retries); // 发起第一次请求
});
};
// HTTP 方法封装
const get = (url, data = {}, headers = {}) => {
return request({
url,
method: 'GET',
data,
headers,
});
};
const post = (url, data = {}, headers = {}) => {
return request({
url,
method: 'POST',
data,
headers,
});
};
const put = (url, data = {}, headers = {}) => {
return request({
url,
method: 'PUT',
data,
headers,
});
};
const del = (url, data = {}, headers = {}) => {
return request({
url,
method: 'DELETE',
data,
headers,
});
};
// 调用请求拦截器和响应拦截器
requestInterceptor();
responseInterceptor();
// 导出封装的请求方法
export default {
get,
post,
put,
del,
retryRequest, // 导出重试请求方法
};
说明
请求拦截器:requestInterceptor 函数会在每次请求之前,自动在请求头中加入 Authorization(如果存在 token)。你可以在 setRequestHeaders 函数中根据需要修改请求头。
响应拦截器:responseInterceptor 会在每次请求响应后,判断响应的状态码。如果是 200,则返回数据。如果是 401(未授权),会跳转到登录页。
错误处理:统一处理错误,比如 Token 过期、网络请求失败等。
请求重试:retryRequest 方法可以设置请求失败时进行自动重试。
六、使用封装好的请求
现在你可以在项目中任何地方使用封装好的请求方法,发送 GET、POST 等请求。示例如下:
import request from '@/utils/request';
// 使用 GET 请求
request.get('/api/user', { userId: 123 })
.then((res) => {
console.log('GET 请求成功:', res);
})
.catch((err) => {
console.error('GET 请求失败:', err);
});
// 使用 POST 请求
request.post('/api/login', { username: 'test', password: '123456' })
.then((res) => {
console.log('POST 请求成功:', res);
})
.catch((err) => {
console.error('POST 请求失败:', err);
});
// 使用重试请求
request.retryRequest({ url: '/api/retry', method: 'GET' })
.then((res) => {
console.log('重试请求成功:', res);
})
.catch((err) => {
console.error('重试请求失败:', err);
});
总结
通过上面的封装,你实现了以下几个功能:
1、请求拦截:在请求发起前设置 Authorization 头部。
2、响应拦截:在响应回来时统一处理成功和错误的情况。
3、重试机制:在请求失败时自动重试,增加了网络请求的健壮性。
4、封装了常用请求方法:封装了 GET、POST、PUT、DELETE 请求,简化了代码。
这样,你就可以在 uni-app 项目中方便地使用这些请求方法了。如果需要更多的功能,比如全局 loading、分页处理等,可以继续扩展这个封装。