UniApp 中封装 HTTP 请求与 Token 管理(附Demo)

目录

  • [1. 基本知识](#1. 基本知识)
  • [2. Demo](#2. Demo)
  • [3. 拓展](#3. 拓展)

1. 基本知识

从实战代码中学习,上述实战代码来源:芋道源码/yudao-mall-uniapp

该代码中,通过自定义 request 函数对 HTTP 请求进行了统一管理,并且结合了 Token 认证机制

  1. 请求封装原理,request 函数是对 uni.request 的一个封装:
  • 动态设置请求头:根据 config 的配置,决定是否需要在请求头中附加 Authorization(Bearer Token)。Token 是从本地存储中获取的
  • 根据环境区分不同的 Base URL:根据当前的开发环境(development 或 production),动态设置请求的基础 URL(baseUrl)
  • 统一处理请求参数:config.params 会被转化成查询字符串,拼接到请求的 URL 后面
  • Promise 封装异步操作:请求通过 uni.request 发出,并将返回的 response 数据封装为一个 Promise,使得调用 request 的地方可以使用 then 或 catch 来处理结果
  1. Token 认证管理原理
  • Token 存储:uni.setStorageSync 和 uni.getStorageSync 被用来在客户端本地存储 ACCESS_TOKEN 和 REFRESH_TOKEN,这两个 Token 被用于身份验证
  • 获取 Token:在每次 HTTP 请求时,首先会检查请求是否需要 Token(通过 config.headers.isToken 判断)。如果需要,就从本地存储中获取 AccessToken 并加入到请求头中
  • Token 过期处理:当请求返回的状态码为 401 时,表示 Token 已过期,此时会弹出提示框,让用户重新登录并清除旧的 Token
  1. 错误处理机制
  • 网络错误:封装了常见的网络错误(如超时、服务器错误等),并提供了友好的提示
  • 接口返回错误:统一处理接口返回的错误,错误信息根据 res.data.code 的值来决定,如果返回的是 500 错误或其他非 200 的错误,则通过 toast 提示给用户
  • 401 错误处理:当返回状态码为 401 时,表示 Token 过期或无效,代码会自动处理登出流程

2. Demo

根据实战中的Demo,给出一版通用的Demo:

封装request的时候,需要与token结合:

js 复制代码
// utils/request.js
import { getAccessToken, setToken, removeToken } from '@/utils/auth';
import config from '@/config';
import errorCode from '@/utils/errorCode';
import { toast, showConfirm } from '@/utils/common';

let timeout = 10000;
let baseUrl = process.env.NODE_ENV === 'development' ? config.devbaseUrl : config.prodbaseUrl;

const request = config => {
  const isToken = (config.headers || {}).isToken === false;
  config.header = config.header || {};
  
  if (getAccessToken() && !isToken) {
    config.header['Authorization'] = 'Bearer ' + getAccessToken();
  }

  config.header['tenant-id'] = '1'; // 强制设置租户 ID

  if (config.params) {
    let url = config.url + '?' + tansParams(config.params);
    url = url.slice(0, -1);
    config.url = url;
  }

  return new Promise((resolve, reject) => {
    uni.request({
      method: config.method || 'get',
      timeout: config.timeout || timeout,
      url: config.baseUrl || baseUrl + config.url,
      data: config.data,
      header: config.header,
      dataType: 'json'
    }).then(response => {
      let [error, res] = response;
      if (error) {
        toast('后端接口连接异常');
        reject('后端接口连接异常');
        return;
      }
      const code = res.data.code || 200;
      const msg = errorCode[code] || res.data.msg || errorCode['default'];
      
      if (code === 401) {
        showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
          if (res.confirm) {
            removeToken();
            uni.reLaunch({ url: '/pages/login' });
          }
        });
        reject('无效的会话,或者会话已过期,请重新登录。');
      } else if (code === 500) {
        toast(msg);
        reject('500');
      } else if (code !== 200) {
        toast(msg);
        reject(code);
      }
      resolve(res.data);
    }).catch(error => {
      let { message } = error;
      if (message === 'Network Error') message = '后端接口连接异常';
      else if (message.includes('timeout')) message = '系统接口请求超时';
      else if (message.includes('Request failed with status code')) message = '系统接口' + message.substr(message.length - 3) + '异常';
      toast(message);
      reject(error);
    });
  });
};

export default request;

对应的token文件:

js 复制代码
// utils/auth.js
const AccessTokenKey = 'ACCESS_TOKEN';
const RefreshTokenKey = 'REFRESH_TOKEN';

export function getAccessToken() {
  return uni.getStorageSync(AccessTokenKey);
}

export function getRefreshToken() {
  return uni.getStorageSync(RefreshTokenKey);
}

export function setToken(token) {
  uni.setStorageSync(AccessTokenKey, token.accessToken);
  uni.setStorageSync(RefreshTokenKey, token.refreshToken);
}

export function removeToken() {
  uni.removeStorageSync(AccessTokenKey);
  uni.removeStorageSync(RefreshTokenKey);
}

相关接口请求:

js 复制代码
// 在页面中调用封装的请求方法
import request from '@/utils/request';

export default {
  methods: {
    fetchData() {
      request({
        url: '/api/getData',
        method: 'GET',
        params: { id: 123 }
      }).then(response => {
        console.log('数据:', response);
      }).catch(error => {
        console.log('请求失败:', error);
      });
    }
  }
}

3. 拓展

process.env.NODE_ENV 是 Node.js 环境中用于获取当前应用运行环境的一个变量

在大多数前端框架(如 Vue、React)以及后端框架(如 Express)中,process.env.NODE_ENV 被广泛用于区分不同的开发环境

前端vue中可能已经标明了

在开发模式下:NODE_ENV=development npm run dev

在生产模式下:NODE_ENV=production npm run build

在 npm 脚本中,可以通过 cross-env 等工具来跨平台设置环境变量:

java 复制代码
"scripts": {
  "dev": "cross-env NODE_ENV=development vue-cli-service serve",
  "build": "cross-env NODE_ENV=production vue-cli-service build"
}

另外一个接口超时时间,全局默认是20秒,如果时长不对,可以在单独某个接口设置:

js 复制代码
// 上传图片
uploadImage(data) {
  return upload({
    url: '/infra/file/upload',
    method: 'upload',
    filePath: data.filePath,
    timeout: 30000  // 设置超时时间为30秒
  });
}
相关推荐
海市公约5 小时前
Vue3组合式API中watch传值生命周期与自定义Hook实战
vue3·生命周期·watch·props·组件通信·defineexpose·自定义hook
摸鱼同学6 小时前
LLM 是什么?从 API 调用到 Token 机制
ai·大模型·llm·token·claudecode
小妖6661 天前
console.log 显示内容不全怎么办
javascript·js·console.log
海市公约1 天前
Vue3组合式API与响应式系统核心机制详解
vue3·computed·reactive·ref·响应式系统·composition api·script setup
阿昌喜欢吃黄桃1 天前
大模型常见参数学习笔记
人工智能·ai·llm·prompt·token
小茴香3532 天前
Vue3路由权限动态管理
前端·前端框架·vue3
abigale032 天前
LangChain 实践4: 7个人AI助手全栈项目:完整拆解+分阶段开发指南
缓存·langchain·prompt·token·rag·lcel
路光.5 天前
uniapp中解决webview在app中调用,有过渡空白问题,增加过渡动效
uni-app·vue·app·uniapp
暗冰ཏོ6 天前
《2026 Vue2 + Vue3 完整学习指南:基础语法、路由缓存、登录拦截、项目实战与面试题》
前端·vue.js·vue·vue3·vue2
padane227 天前
gmssl编译wasm
ubuntu·html·密码学·wasm·js