您好,登录后才能下订单哦!
在现代前端开发中,接口请求是不可避免的一部分。无论是获取数据、提交表单还是与后端进行交互,接口请求都扮演着至关重要的角色。在 uni-app
中,使用 Vue3
进行开发时,如何高效地封装接口请求,成为了一个值得探讨的话题。本文将详细介绍如何在 uni-app
中基于 Vue3
封装接口请求,以提高代码的可维护性和复用性。
在开发过程中,直接使用原生的 fetch
或 axios
进行接口请求是可行的,但随着项目规模的扩大,这种方式会带来一些问题:
通过封装接口请求,我们可以解决上述问题,提高代码的可维护性和复用性。
在 uni-app
中,我们可以基于 Vue3
的 Composition API
来封装接口请求。基本思路如下:
axios
或 uni.request
创建一个统一的请求实例,配置全局的请求头、超时时间等。GET
、POST
、PUT
、DELETE
等)封装成统一的函数。TypeScript
为请求参数和响应数据提供类型支持,提高代码的健壮性。在 uni-app
中,我们可以使用 uni.request
进行网络请求。为了统一管理请求配置,我们可以创建一个请求实例。
// utils/request.js
import { ref } from 'vue';
const BASE_URL = 'https://api.example.com'; // 基础URL
const request = (options) => {
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header,
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
},
});
});
};
export default request;
在这个示例中,我们创建了一个 request
函数,它接受一个 options
对象作为参数,包含了请求的 url
、method
、data
等信息。通过 uni.request
发送请求,并在请求成功或失败时分别调用 resolve
和 reject
。
接下来,我们可以基于 request
函数封装常用的请求方法,如 GET
、POST
、PUT
、DELETE
等。
// utils/request.js
const get = (url, params = {}, header = {}) => {
return request({
url,
method: 'GET',
data: params,
header,
});
};
const post = (url, data = {}, header = {}) => {
return request({
url,
method: 'POST',
data,
header,
});
};
const put = (url, data = {}, header = {}) => {
return request({
url,
method: 'PUT',
data,
header,
});
};
const del = (url, data = {}, header = {}) => {
return request({
url,
method: 'DELETE',
data,
header,
});
};
export { get, post, put, del };
通过这种方式,我们可以在业务代码中直接使用 get
、post
等方法,而不需要每次都手动配置请求方法和请求体。
在实际开发中,我们通常需要在请求发送前和响应返回后进行一些统一的处理。例如,在请求发送前添加 token
,在响应返回后处理错误信息等。
我们可以通过 request
函数的 header
参数来实现请求拦截,通过 success
和 fail
回调来实现响应拦截。
// utils/request.js
const request = (options) => {
return new Promise((resolve, reject) => {
// 请求拦截:添加 token
const token = uni.getStorageSync('token');
if (token) {
options.header = {
...options.header,
Authorization: `Bearer ${token}`,
};
}
uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header,
},
success: (res) => {
// 响应拦截:处理错误信息
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
},
});
});
};
在这个示例中,我们在请求发送前检查本地存储中是否存在 token
,如果存在则将其添加到请求头中。在响应返回后,我们检查状态码,如果状态码为 200
则返回数据,否则返回错误信息。
为了便于维护和修改,我们可以将所有的接口地址集中管理。例如,创建一个 api.js
文件,将所有接口地址定义在其中。
// api.js
export const API = {
// 用户相关接口
USER: {
LOGIN: '/user/login', // 登录
REGISTER: '/user/register', // 注册
INFO: '/user/info', // 获取用户信息
},
// 文章相关接口
ARTICLE: {
LIST: '/article/list', // 文章列表
DETL: '/article/detail', // 文章详情
CREATE: '/article/create', // 创建文章
UPDATE: '/article/update', // 更新文章
DELETE: '/article/delete', // 删除文章
},
};
在业务代码中,我们可以通过 API.USER.LOGIN
等方式引用接口地址,避免硬编码。
import { get, post } from '@/utils/request';
import { API } from '@/api';
// 登录
const login = (params) => {
return post(API.USER.LOGIN, params);
};
// 获取用户信息
const getUserInfo = () => {
return get(API.USER.INFO);
};
如果项目中使用 TypeScript
,我们可以为请求参数和响应数据提供类型支持,以提高代码的健壮性。
// types/user.ts
export interface LoginParams {
username: string;
password: string;
}
export interface UserInfo {
id: number;
username: string;
email: string;
}
// api/user.ts
import { post, get } from '@/utils/request';
import { API } from '@/api';
import { LoginParams, UserInfo } from '@/types/user';
export const login = (params: LoginParams): Promise<UserInfo> => {
return post(API.USER.LOGIN, params);
};
export const getUserInfo = (): Promise<UserInfo> => {
return get(API.USER.INFO);
};
通过这种方式,我们可以在编写代码时获得类型提示,减少因类型错误导致的 bug。
在实际开发中,接口请求可能会因为各种原因失败,如网络错误、服务器错误、权限不足等。为了提高用户体验,我们需要对这些错误进行统一的处理。
我们可以在 request
函数中添加错误处理逻辑,并根据不同的错误类型进行不同的处理。
// utils/request.js
const request = (options) => {
return new Promise((resolve, reject) => {
// 请求拦截:添加 token
const token = uni.getStorageSync('token');
if (token) {
options.header = {
...options.header,
Authorization: `Bearer ${token}`,
};
}
uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header,
},
success: (res) => {
// 响应拦截:处理错误信息
if (res.statusCode === 200) {
resolve(res.data);
} else {
// 处理不同的错误状态码
switch (res.statusCode) {
case 401:
// 未授权,跳转到登录页面
uni.navigateTo({ url: '/pages/login/index' });
break;
case 404:
// 资源未找到
uni.showToast({ title: '资源未找到', icon: 'none' });
break;
case 500:
// 服务器错误
uni.showToast({ title: '服务器错误', icon: 'none' });
break;
default:
// 其他错误
uni.showToast({ title: '请求失败', icon: 'none' });
break;
}
reject(res.data);
}
},
fail: (err) => {
// 网络错误
uni.showToast({ title: '网络错误', icon: 'none' });
reject(err);
},
});
});
};
在这个示例中,我们根据不同的状态码进行不同的错误处理。例如,当状态码为 401
时,跳转到登录页面;当状态码为 404
时,提示资源未找到;当状态码为 500
时,提示服务器错误。
在某些情况下,我们可能需要取消正在进行的请求。例如,当用户快速切换页面时,之前的请求可能已经不再需要。为了避免不必要的网络请求,我们可以实现请求取消功能。
在 uni.request
中,我们可以通过 abort
方法来取消请求。为了实现请求取消功能,我们可以在 request
函数中返回一个包含 abort
方法的对象。
// utils/request.js
const request = (options) => {
let requestTask = null;
const promise = new Promise((resolve, reject) => {
// 请求拦截:添加 token
const token = uni.getStorageSync('token');
if (token) {
options.header = {
...options.header,
Authorization: `Bearer ${token}`,
};
}
requestTask = uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header,
},
success: (res) => {
// 响应拦截:处理错误信息
if (res.statusCode === 200) {
resolve(res.data);
} else {
// 处理不同的错误状态码
switch (res.statusCode) {
case 401:
// 未授权,跳转到登录页面
uni.navigateTo({ url: '/pages/login/index' });
break;
case 404:
// 资源未找到
uni.showToast({ title: '资源未找到', icon: 'none' });
break;
case 500:
// 服务器错误
uni.showToast({ title: '服务器错误', icon: 'none' });
break;
default:
// 其他错误
uni.showToast({ title: '请求失败', icon: 'none' });
break;
}
reject(res.data);
}
},
fail: (err) => {
// 网络错误
uni.showToast({ title: '网络错误', icon: 'none' });
reject(err);
},
});
});
return {
promise,
abort: () => {
if (requestTask) {
requestTask.abort();
}
},
};
};
在业务代码中,我们可以通过 abort
方法来取消请求。
const { promise, abort } = request({
url: API.USER.INFO,
method: 'GET',
});
// 取消请求
abort();
在某些情况下,我们可能需要同时发送多个请求,并在所有请求完成后进行统一处理。例如,在页面加载时,我们需要同时获取用户信息和文章列表。
我们可以使用 Promise.all
来处理并发请求。
import { get } from '@/utils/request';
import { API } from '@/api';
const fetchData = async () => {
try {
const [userInfo, articleList] = await Promise.all([
get(API.USER.INFO),
get(API.ARTICLE.LIST),
]);
console.log('用户信息:', userInfo);
console.log('文章列表:', articleList);
} catch (error) {
console.error('请求失败:', error);
}
};
在这个示例中,我们使用 Promise.all
同时发送两个请求,并在所有请求完成后处理返回的数据。
在某些情况下,我们可能需要对请求结果进行缓存,以减少不必要的网络请求。例如,当用户多次访问同一个页面时,我们可以缓存第一次请求的结果,并在后续访问时直接使用缓存数据。
我们可以使用 localStorage
或 sessionStorage
来实现请求缓存。
// utils/request.js
const requestWithCache = (options) => {
return new Promise((resolve, reject) => {
const cacheKey = options.url + JSON.stringify(options.data || {});
const cacheData = uni.getStorageSync(cacheKey);
if (cacheData) {
resolve(cacheData);
return;
}
request(options).then((res) => {
uni.setStorageSync(cacheKey, res);
resolve(res);
}).catch((err) => {
reject(err);
});
});
};
在业务代码中,我们可以使用 requestWithCache
方法来发送带有缓存的请求。
import { requestWithCache } from '@/utils/request';
import { API } from '@/api';
const fetchData = async () => {
try {
const data = await requestWithCache({
url: API.ARTICLE.LIST,
method: 'GET',
});
console.log('文章列表:', data);
} catch (error) {
console.error('请求失败:', error);
}
};
在实际开发中,我们可能需要上传文件。uni-app
提供了 uni.uploadFile
方法来实现文件上传。
我们可以基于 uni.uploadFile
封装一个文件上传方法。
// utils/request.js
const uploadFile = (options) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: BASE_URL + options.url,
filePath: options.filePath,
name: options.name || 'file',
formData: options.formData || {},
header: {
'Content-Type': 'multipart/form-data',
...options.header,
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
},
});
});
};
在业务代码中,我们可以使用 uploadFile
方法来上传文件。
import { uploadFile } from '@/utils/request';
import { API } from '@/api';
const uploadImage = async (filePath) => {
try {
const result = await uploadFile({
url: API.UPLOAD.IMAGE,
filePath,
name: 'image',
});
console.log('上传成功:', result);
} catch (error) {
console.error('上传失败:', error);
}
};
在某些情况下,我们可能需要下载文件。uni-app
提供了 uni.downloadFile
方法来实现文件下载。
我们可以基于 uni.downloadFile
封装一个文件下载方法。
// utils/request.js
const downloadFile = (options) => {
return new Promise((resolve, reject) => {
uni.downloadFile({
url: BASE_URL + options.url,
header: {
...options.header,
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath);
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
},
});
});
};
在业务代码中,我们可以使用 downloadFile
方法来下载文件。
import { downloadFile } from '@/utils/request';
import { API } from '@/api';
const downloadImage = async (url) => {
try {
const filePath = await downloadFile({
url: API.DOWNLOAD.IMAGE,
});
console.log('下载成功:', filePath);
} catch (error) {
console.error('下载失败:', error);
}
};
在开发过程中,我们可能会遇到跨域问题。uni-app
提供了 uni.request
的 withCredentials
选项来处理跨域请求时的 cookie
传递。
“javascript
// utils/request.js
const request = (options) => {
return new Promise((resolve, reject) => {
// 请求拦截:添加 token
const token = uni.getStorageSync('token');
if (token) {
options.header = {
...options.header,
Authorization:
Bearer ${token}`,
};
}
uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header,
},
withCredentials: true, // 允许携带 cookie
success: (res) => {
// 响应拦截:处理错误信息
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res.data);
}
},
fail: (err) =>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。