1. 封装的目的

2.基础准备
pnpm add axios
# 若需要处理 TypeScript 类型(可选),额外安装
pnpm add @types/axios -D
3.封装通用请求实例(仅参考)
// 引入 axios
import axios from 'axios'
// 1. 创建 axios 实例,配置基础参数
const service = axios.create({
// 基础请求地址:区分开发/生产环境(关键!避免打包后修改地址)
baseURL: process.env.NODE_ENV === 'development'
? 'http://localhost:8080/api' // 开发环境(后端本地/测试服务器地址)
: 'https://prod-api.xxx.com/api', // 生产环境(线上服务器地址)
// 请求超时时间:超过该时间未响应,视为请求失败
timeout: 10000,
// 统一请求头(可选,根据后端要求配置)
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
// 2. 请求拦截器:发送请求前做的处理(如添加 token、修改请求参数格式)
service.interceptors.request.use(
(config) => {
// 【常见场景 1】添加用户登录 token(后端需要身份验证时)
// 从 uni-app 本地存储中获取 token(登录后存入)
const token = uni.getStorageSync('userToken')
if (token) {
// 给请求头添加 token,字段名(Authorization)按后端要求修改(如 token、X-Token)
config.headers.Authorization = `Bearer ${token}`
}
// 【常见场景 2】如果是 GET 请求,统一处理参数格式(可选)
// if (config.method === 'get') {
// config.params = { ...config.params } // 可添加额外公共参数,如 timestamp: Date.now()
// }
// 【常见场景 3】如果是上传文件(FormData 格式),修改请求头
// if (config.data instanceof FormData) {
// config.headers['Content-Type'] = 'multipart/form-data'
// }
return config
},
(error) => {
// 请求发送失败(如网络中断、配置错误)的处理
console.error('请求发送失败:', error)
return Promise.reject(error)
}
)
// 3. 响应拦截器:收到后端响应后做的处理(如统一解析数据、处理错误码)
service.interceptors.response.use(
(response) => {
// 取出后端返回的核心数据(一般后端会返回 { code: 200, data: {}, msg: '成功' } 格式)
const res = response.data
// 【常见场景 1】统一处理成功响应:只返回核心 data,简化接口调用
if (res.code === 200 || res.code === 0) { // 后端成功码按实际约定修改(200/0 最常用)
return res.data // 后续接口调用时,直接拿到 data 数据,无需再解构
}
// 【常见场景 2】统一处理业务错误(如参数错误、token 过期、无权限)
else {
// 1. 弹出错误提示(uni-app 内置提示框)
uni.showToast({
title: res.msg || '请求失败',
icon: 'none',
duration: 2000
})
// 2. 特殊错误码单独处理(如 token 过期,跳转登录页)
if (res.code === 401) { // 401 一般代表未登录/token 过期
uni.showModal({
title: '提示',
content: '登录状态已过期,请重新登录',
showCancel: false,
success: () => {
// 清除本地 token,跳转登录页
uni.removeStorageSync('userToken')
uni.redirectTo({ url: '/pages/login/login' })
}
})
}
// 3. 把错误抛出去,便于接口调用时单独处理(可选)
return Promise.reject(new Error(res.msg || '业务请求失败'))
}
},
(error) => {
// 【常见场景 3】处理网络错误/服务器错误(如 404、500、请求超时)
console.error('响应处理失败:', error)
const errMsg = error.message || '网络异常,请稍后重试'
// 弹出错误提示
uni.showToast({
title: errMsg,
icon: 'none',
duration: 2000
})
return Promise.reject(error)
}
)
// 4. 导出封装好的 axios 实例,供后续接口调用
export default service
4.api封装接口在不同情况下如何写
基于上面封装的 request 实例,按业务模块拆分接口(如用户模块、商品模块),每个接口对应后端的一个接口地址。
只需配置「请求方法、接口路径、请求参数」即可。
参数传递
- GET请求用params:参数自动拼在URL后,适合少量查询参数
- POST/PUT请求用data:参数放在请求体中,适合传递大量提交/更新数据
- 路径参数(如/{id}):直接用反引号拼写在url中
每个接口返回 request(...)/http(...):本质是返回一个 Promise 对象,后续调用时可使用 async/await 或 .then()处理。
统一步骤
// 引入封装好的 axios 实例
import request(http) from '@/utils/request'
第一种方法
// 【用户模块接口】
// 场景 1:GET 请求(查询数据,参数拼在 URL 上)
// 示例:获取用户信息(后端接口:GET /user/info,参数:userId(可选,从 token 解析也可))
export const getUserInfo = (userId) => {
return request({
method: 'GET',
url: '/user/info', // 接口路径(拼接在 baseURL 后面,完整地址:baseURL + /user/info
params: { userId } // GET 请求参数:会自动拼在 URL 后,格式:?userId=xxx
})
}
第二种方法
// 场景 2:POST 请求(提交数据,参数放在请求体中)
// 示例:用户登录(后端接口:POST /user/login,参数:username、password)
export const userLogin = (data) => {
return request({
method: 'POST',
url: '/user/login',
data: data // POST 请求参数:放在请求体中,格式为 JSON(对应 request.js 中的 Content-Type)
})
}
第三种方法
// 场景 3:PUT 请求(更新数据,全量更新)
// 示例:修改用户昵称(后端接口:PUT /user/nickname,参数:userId、nickname)
export const updateUserNickname = (data) => {
return request({
method: 'PUT',
url: '/user/nickname',
data: data
})
}
第四种方法
// 场景 4:DELETE 请求(删除数据)
// 示例:删除用户地址(后端接口:DELETE /user/address/{addressId},参数:addressId(路径参数))
export const deleteUserAddress = (addressId) => {
return request({
method: 'DELETE',
url: `/user/address/${addressId}` // 路径参数:直接拼接在 URL 中(注意用反引号 ``)
})
}
第五种方法
// 场景 5:上传文件(FormData 格式,需配合 request.js 中的请求头修改)
// 示例:上传用户头像(后端接口:POST /user/avatar)
export const uploadUserAvatar = (file) => {
// 创建 FormData 实例
const formData = new FormData()
// 添加文件(字段名 'avatar' 按后端要求修改)
formData.append('avatar', file)
// 发起请求
return request({
method: 'POST',
url: '/user/avatar',
data: formData,
// 覆盖默认请求头(对应 request.js 中的注释场景 3)
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
5. 在 页面/组件中调用接口
导入接口→调用接口→处理返回数据
<template>
<view class="login-container">
<input v-model="username" placeholder="请输入用户名" />
<input v-model="password" type="password" placeholder="请输入密码" />
<button @click="handleLogin">登录</button>
</view>
</template>
<script setup>
import { ref } from 'vue'
// 方式 1:直接从模块导入(适合接口较少时)
import { userLogin } from '@/api/user'
// 方式 2:从统一导出文件导入(适合接口较多时)
// import { userLogin } from '@/api'
// 定义表单数据
const username = ref('')
const password = ref('')
// 登录按钮点击事件
const handleLogin = async () => {
// 1. 表单验证(可选,前端先做基础校验,减少无效请求)
if (!username.value || !password.value) {
uni.showToast({ title: '请输入用户名和密码', icon: 'none' })
return
}
try {
// 2. 调用封装的登录接口,传递参数(对象格式,对应后端要求)
const res = await userLogin({
username: username.value,
password: password.value
})
// 3. 处理接口返回数据(res 就是后端返回的 res.data,已在 request.js 中处理)
console.log('登录成功,用户信息:', res)
// 存储 token 到本地(供后续接口请求使用)
uni.setStorageSync('userToken', res.token)
// 跳转首页
uni.switchTab({ url: '/pages/index/index' })
} catch (error) {
// 4. 处理接口调用失败(如业务错误、网络错误,也可省略,因为 request.js 已做统一提示)
console.error('登录失败:', error)
}
}
</script>
6.遇到不同的后端接口(适配改动)
1
后端接口场景 :基础地址变更
对应的修改位置 :utils/request.js 的 baseURL
具体操作 :直接修改开发 / 生产环境的地址即可;若有多环境(测试 / 预发布),可新增环境变量配置。
2
后端接口场景 :身份验证字段不是 Authorization
对应的修改位置 :utils/request.js 请求拦截器
具体操作 :把 config.headers.Authorization 改为后端要求的字段,如 config.headers.token。
3
后端接口场景 :响应成功码不是 200/0
对应的修改位置 :utils/request.js 响应拦截器
具体操作 :把 res.code === 200/res.code === 0改为后端约定的成功码,如res.code === 20000。
4
后端接口场景 :响应格式不是 {code, data, msg}
对应的修改位置 :utils/request.js 响应拦截器
具体操作 :调整 res 的解构方式,比如后端返回 {success: true, result: {}, message: ''},则修改为:if (res.success) { return res.result }。
5
后端接口场景 :需要传递 FormData 上传文件
对应的修改位置 :具体接口(如 api/user.js)
具体操作 :创建 FormData 实例,添加文件 / 参数,覆盖请求头为 multipart/form-data。
6
后端接口场景 :接口需要跨域(开发环境)
对应的修改位置 :uni-app 项目根目录创建 vite.config.js
具体操作 :配置 vite 代理,转发请求,避免跨域错误(下面补充)。
7.补充:开发环境跨域解决方案(vite 代理)
如果开发时出现「Access to XMLHttpRequest at ... from origin ... has been blocked by CORS policy」跨域错误,可在项目根目录创建 vite.config.js,配置代理转发:
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
export default defineConfig({
plugins: [uni()],
server: {
proxy: {
// 匹配所有以 /api 开头的请求路径
'/api': {
target: 'http://localhost:8080', // 后端真实接口地址(去掉 /api)
changeOrigin: true, // 开启跨域模拟
rewrite: (path) => path.replace(/^\/api/, '') // 重写路径:去掉 /api 前缀(根据后端接口是否带 /api 调整)
}
}
}
})