详细讲解-uniapp封装request请求

发布于:2025-08-09 ⋅ 阅读:(22) ⋅ 点赞:(0)

关注大师不迷路,大师带你上高度~


前言

关注大师不迷路,大师带你上高度~
在使用 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、分页处理等,可以继续扩展这个封装。


网站公告

今日签到

点亮在社区的每一天
去签到