首页 云计算

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率

分类:云计算
字数: (5788)
阅读: (3998)
内容摘要:UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率,

在 UniApp 项目开发中,经常需要与后端 API 进行数据交互。如果每个页面都直接使用 uni.request 发起请求,会导致代码冗余、难以维护。本文将深入探讨 UniApp 请求接口封装的最佳实践,帮助开发者告别重复劳动,提升开发效率,并在实际项目中更加高效地处理请求。

问题场景:未封装的请求方式的弊端

假设我们需要在多个页面获取用户信息,如果直接使用 uni.request,代码可能如下所示:

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率
uni.request({
  url: 'https://api.example.com/user/info',
  method: 'GET',
  success: (res) => {
    if (res.statusCode === 200) {
      this.userInfo = res.data;
    } else {
      uni.showToast({ title: '获取用户信息失败', icon: 'none' });
    }
  },
  fail: (err) => {
    uni.showToast({ title: '网络错误', icon: 'none' });
  }
});

这种方式存在以下问题:

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率
  • 代码冗余: 相同的代码需要在多个页面重复编写。
  • 难以维护: 如果 API 地址或请求头发生变化,需要修改所有使用 uni.request 的地方。
  • 错误处理分散: 每个请求都需要单独处理错误,增加了代码复杂度。

底层原理:Promise 封装与拦截器机制

为了解决上述问题,我们可以对 uni.request 进行 Promise 封装,并利用拦截器机制实现统一的请求处理。Promise 可以将异步请求转换为同步操作,方便链式调用和错误处理。拦截器则可以在请求发送前和响应返回后进行统一处理,例如添加请求头、处理错误状态码等。

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率

Promise 封装

我们可以将 uni.request 封装成一个返回 Promise 对象的函数:

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率
function request(options) {
  return new Promise((resolve, reject) => {
    uni.request({
      ...options,
      success: (res) => {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve(res.data);
        } else {
          reject(res);
        }
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
}

export default request;

拦截器机制

我们可以使用类似 Axios 的拦截器机制,在请求发送前和响应返回后进行统一处理。例如,可以在请求发送前添加 token,在响应返回后处理错误状态码。

代码解决方案:详细封装步骤

下面是一个完整的 UniApp 请求接口封装方案:

  1. 创建 request.js 文件:
const baseURL = 'https://api.example.com'; // 基础URL

let pendingRequests = 0; // 并发请求计数器

function showLoading() {
  if (pendingRequests === 0) {
    uni.showLoading({
      title: '加载中...'
    });
  }
  pendingRequests++;
}

function hideLoading() {
  pendingRequests--;
  if (pendingRequests === 0) {
    uni.hideLoading();
  }
}

function request(options) {
  return new Promise((resolve, reject) => {
    // 请求拦截器
    if (options.showLoading !== false) { // 可选参数,控制是否显示 loading
      showLoading();
    }

    options.url = baseURL + options.url;
    options.header = {
      ...options.header,
      'Authorization': uni.getStorageSync('token') || '' // 从 Storage 中获取 token
    };

    uni.request({
      ...options,
      success: (res) => {
        // 响应拦截器
        if (options.showLoading !== false) {
          hideLoading();
        }

        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve(res.data);
        } else if (res.statusCode === 401) {
          // token 过期,重新登录
          uni.navigateTo({
            url: '/pages/login/login'
          });
          reject(res);
        } else {
          uni.showToast({
            title: res.data.message || '请求失败',
            icon: 'none'
          });
          reject(res);
        }
      },
      fail: (err) => {
        if (options.showLoading !== false) {
          hideLoading();
        }
        uni.showToast({
          title: '网络错误', icon: 'none'
        });
        reject(err);
      }
    });
  });
}

// 封装 GET、POST、PUT、DELETE 方法
request.get = function(url, data, options = {}) {
  options.method = 'GET';
  options.url = url;
  options.data = data;
  return request(options);
};

request.post = function(url, data, options = {}) {
  options.method = 'POST';
  options.url = url;
  options.data = data;
  return request(options);
};

request.put = function(url, data, options = {}) {
  options.method = 'PUT';
  options.url = url;
  options.data = data;
  return request(options);
};

request.delete = function(url, data, options = {}) {
  options.method = 'DELETE';
  options.url = url;
  options.data = data;
  return request(options);
};

export default request;
  1. 在页面中使用:
import request from '@/utils/request.js';

export default {
  data() {
    return {
      userInfo: {}
    }
  },
  onLoad() {
    this.getUserInfo();
  },
  methods: {
    async getUserInfo() {
      try {
        const res = await request.get('/user/info');
        this.userInfo = res;
      } catch (err) {
        console.error(err);
      }
    }
  }
}

上述代码通过 import request from '@/utils/request.js'; 导入封装好的 request 对象,然后使用 request.get() 方法发起 GET 请求,获取用户信息。async/await 语法使异步代码更加简洁易懂。

实战避坑经验总结

  • baseUrl 配置: 将 API 的基础 URL 放在 request.js 文件中统一管理,方便修改。
  • Token 管理: 将 Token 存储在 Storage 中,并在请求头中携带。 token的续签机制也很重要,可以设置过期时间,在拦截器中判断是否需要刷新token。可以考虑使用JWT(JSON Web Token)。
  • 错误处理: 统一处理错误状态码,例如 401 状态码跳转到登录页面。
  • Loading 提示: 在请求发送前显示 Loading 提示,请求完成后隐藏 Loading 提示,提升用户体验。可以使用节流或防抖来优化 loading 的显示,避免频繁闪烁。
  • 并发控制: 限制并发请求数量,避免服务器压力过大。通过维护一个 pending 请求队列,超过最大并发数时,将请求放入队列中等待。
  • Nginx 反向代理: 在生产环境中,通常会使用 Nginx 作为反向代理服务器,对 API 请求进行负载均衡和安全防护。 Nginx 可以配置 upstream 模块实现后端服务器的负载均衡,并设置缓存策略来提升性能。
  • 宝塔面板: 可以使用宝塔面板快速搭建 Nginx 环境,简化配置过程。
  • 并发连接数: 需要根据服务器的硬件配置和网络带宽,合理设置 Nginx 的并发连接数和 worker 进程数,避免服务器崩溃。

通过以上封装和优化,可以有效提高 UniApp 项目的开发效率和代码质量。记住,持续学习和实践是成为优秀架构师的关键。希望本文对你的项目有所帮助。

UniApp 请求接口封装最佳实践:告别代码冗余,提升开发效率

转载请注明出处: 键盘上的咸鱼

本文的链接地址: http://m.acea2.store/blog/940364.SHTML

本文最后 发布于2026-04-14 22:42:45,已经过了13天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 四川担担面 3 天前
    并发控制那里,有没有具体的代码实现例子?