uni-app vue3接口请求怎么封装

发布时间:2023-05-04 10:09:19 作者:iii
来源:亿速云 阅读:474

uni-app Vue3 接口请求怎么封装

在现代前端开发中,接口请求是不可避免的一部分。无论是获取数据、提交表单还是与后端进行交互,接口请求都扮演着至关重要的角色。在 uni-app 中,使用 Vue3 进行开发时,如何高效地封装接口请求,成为了一个值得探讨的话题。本文将详细介绍如何在 uni-app 中基于 Vue3 封装接口请求,以提高代码的可维护性和复用性。

1. 为什么需要封装接口请求?

在开发过程中,直接使用原生的 fetchaxios 进行接口请求是可行的,但随着项目规模的扩大,这种方式会带来一些问题:

  1. 代码冗余:每个请求都需要重复编写请求头、请求体、错误处理等代码。
  2. 维护困难:当接口地址或请求方式发生变化时,需要在多个地方进行修改。
  3. 可读性差:分散的请求代码使得项目的可读性降低,不利于团队协作。
  4. 安全性问题:直接在业务代码中暴露接口地址和请求参数,可能会带来安全隐患。

通过封装接口请求,我们可以解决上述问题,提高代码的可维护性和复用性。

2. 封装接口请求的基本思路

uni-app 中,我们可以基于 Vue3Composition API 来封装接口请求。基本思路如下:

  1. 创建统一的请求实例:使用 axiosuni.request 创建一个统一的请求实例,配置全局的请求头、超时时间等。
  2. 封装请求方法:将常用的请求方法(如 GETPOSTPUTDELETE 等)封装成统一的函数。
  3. 处理请求拦截和响应拦截:在请求发送前和响应返回后,进行统一的处理,如添加请求头、处理错误等。
  4. 统一管理接口地址:将所有的接口地址集中管理,方便维护和修改。
  5. 提供类型支持:使用 TypeScript 为请求参数和响应数据提供类型支持,提高代码的健壮性。

3. 创建统一的请求实例

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 对象作为参数,包含了请求的 urlmethoddata 等信息。通过 uni.request 发送请求,并在请求成功或失败时分别调用 resolvereject

4. 封装请求方法

接下来,我们可以基于 request 函数封装常用的请求方法,如 GETPOSTPUTDELETE 等。

// 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 };

通过这种方式,我们可以在业务代码中直接使用 getpost 等方法,而不需要每次都手动配置请求方法和请求体。

5. 处理请求拦截和响应拦截

在实际开发中,我们通常需要在请求发送前和响应返回后进行一些统一的处理。例如,在请求发送前添加 token,在响应返回后处理错误信息等。

我们可以通过 request 函数的 header 参数来实现请求拦截,通过 successfail 回调来实现响应拦截。

// 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 则返回数据,否则返回错误信息。

6. 统一管理接口地址

为了便于维护和修改,我们可以将所有的接口地址集中管理。例如,创建一个 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);
};

7. 提供类型支持

如果项目中使用 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。

8. 处理错误信息

在实际开发中,接口请求可能会因为各种原因失败,如网络错误、服务器错误、权限不足等。为了提高用户体验,我们需要对这些错误进行统一的处理。

我们可以在 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 时,提示服务器错误。

9. 处理请求取消

在某些情况下,我们可能需要取消正在进行的请求。例如,当用户快速切换页面时,之前的请求可能已经不再需要。为了避免不必要的网络请求,我们可以实现请求取消功能。

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();

10. 处理并发请求

在某些情况下,我们可能需要同时发送多个请求,并在所有请求完成后进行统一处理。例如,在页面加载时,我们需要同时获取用户信息和文章列表。

我们可以使用 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 同时发送两个请求,并在所有请求完成后处理返回的数据。

11. 处理请求缓存

在某些情况下,我们可能需要对请求结果进行缓存,以减少不必要的网络请求。例如,当用户多次访问同一个页面时,我们可以缓存第一次请求的结果,并在后续访问时直接使用缓存数据。

我们可以使用 localStoragesessionStorage 来实现请求缓存。

// 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);
  }
};

12. 处理文件上传

在实际开发中,我们可能需要上传文件。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);
  }
};

13. 处理文件下载

在某些情况下,我们可能需要下载文件。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);
  }
};

14. 处理跨域问题

在开发过程中,我们可能会遇到跨域问题。uni-app 提供了 uni.requestwithCredentials 选项来处理跨域请求时的 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) =>
推荐阅读:
  1. uni-app如何使用
  2. 怎么用uni-app制作小程序实现左右菜单联动效果

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

uni-app vue3

上一篇:Vue组件设计Sticky布局效果怎么实现

下一篇:VUE中常用的高级方法有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》