uni-app 网络请求与后端交互完全指南:从基础到实战
在移动应用开发中,网络请求是连接前端与后端的核心桥梁,也是实现数据动态展示、用户交互的关键环节。作为跨平台开发框架的佼佼者,uni-app 提供了一套统一的网络请求方案,既能适配多端(App、小程序、H5 等),又能满足复杂业务场景的需求。本文将从基础用法入手,逐步深入到实战技巧,帮助你彻底掌握 uni-app 与后端的交互逻辑。
一、uni-app 网络请求的核心 API:uni.request ()
uni-app 并未引入额外的第三方库(如 axios),而是内置了 uni.request()
方法作为网络请求的统一入口。该方法遵循 Promise 规范,同时兼容回调函数写法,适配所有支持的平台,无需针对不同端做额外适配。
1. 基本语法与参数说明
uni.request()
的核心参数如下(仅列出常用关键参数):
参数名 | 类型 | 说明 | 必选 |
---|---|---|---|
url | String | 后端接口地址(需注意跨域问题) | 是 |
method | String | 请求方法,可选值:GET/POST/PUT/DELETE 等 | 否(默认 GET) |
data | Object/String/ArrayBuffer | 请求参数(GET 会拼接到 URL,POST 会放在请求体) | 否 |
header | Object | 请求头(如 Content-Type、Token 等) | 否 |
success | Function | 请求成功的回调(返回数据在 res.data 中) | 否 |
fail | Function | 请求失败的回调(如网络错误、超时等) | 否 |
complete | Function | 请求完成的回调(无论成功 / 失败都会执行) | 否 |
2. 最简单的 GET 请求案例
以 “获取用户信息” 接口为例,演示基础的 GET 请求:
// 发起 GET 请求获取用户信息
uni.request({url: 'https://api.example.com/user/info', // 后端接口地址method: 'GET',data: {userId: '123456', // 传递给后端的参数token: 'abcdef123456'},success: (res) => {// 请求成功:res 为后端返回的完整数据console.log('用户信息请求成功', res.data);// 通常后端会返回 code(状态码)、message(提示信息)、data(业务数据)if (res.data.code === 200) {// 业务成功:处理数据(如赋值给页面变量)this.userInfo = res.data.data;} else {// 业务失败:提示用户uni.showToast({title: res.data.message,icon: 'none'});}},fail: (err) => {// 请求失败:如网络断开、接口不存在等console.error('用户信息请求失败', err);uni.showToast({title: '网络错误,请稍后重试',icon: 'none'});}
});
3. 常用的 POST 请求案例
POST 请求常用于提交数据(如登录、表单提交),需注意 header
中 Content-Type
的配置(后端通常要求 application/json
或 application/x-www-form-urlencoded
):
// 发起 POST 请求实现用户登录
uni.request({url: 'https://api.example.com/user/login',method: 'POST',header: {'Content-Type': 'application/json' // 明确请求体格式为 JSON},data: {username: 'test123',password: '123456'},success: (res) => {if (res.data.code === 200) {// 登录成功:存储 Token(后续请求需携带)uni.setStorageSync('token', res.data.data.token);// 跳转到首页uni.switchTab({url: '/pages/index/index'});} else {uni.showToast({title: res.data.message || '登录失败',icon: 'none'});}},fail: () => {uni.showToast({title: '网络异常,登录失败',icon: 'none'});}
});
二、实战优化:封装请求工具,避免重复代码
在实际项目中,每个接口都写一次 uni.request()
会导致代码冗余(如重复处理 Token、错误提示、请求头)。因此,封装请求工具是必做的优化步骤,既能提高效率,又能统一管理请求逻辑。
1. 封装思路
-
统一配置基础路径(如
baseURL
),避免每次写完整 URL; -
自动携带 Token(从本地存储中获取);
-
统一处理请求头(如
Content-Type
); -
统一拦截错误(如 Token 过期、网络错误);
-
支持 Promise 链式调用,方便异步处理。
2. 完整的请求工具封装代码
在项目根目录下创建 utils/request.js
文件,代码如下:
// utils/request.js
const request = (options) => {// 1. 基础配置:统一 baseURL(区分开发/生产环境)const baseURL = process.env.NODE_ENV === 'development' ? 'https://dev.api.example.com' // 开发环境接口: 'https://api.example.com'; // 生产环境接口// 2. 合并请求参数:默认方法为 GET,默认请求头为 JSONconst config = {url: baseURL + options.url,method: options.method || 'GET',header: {'Content-Type': 'application/json',// 自动携带 Token(若本地有存储)'Authorization': uni.getStorageSync('token') ? `Bearer ${uni.getStorageSync('token')}` : ''},data: options.data || {}};// 3. 返回 Promise,支持链式调用return new Promise((resolve, reject) => {uni.request({...config,success: (res) => {// 4. 统一处理后端返回的状态码const { code, message, data } = res.data;// Token 过期:清除本地存储,跳转到登录页if (code === 401) {uni.removeStorageSync('token');uni.navigateTo({url: '/pages/login/login'});reject(new Error('Token 已过期,请重新登录'));return;}// 业务成功:返回核心数据if (code === 200) {resolve(data);} else {// 业务失败:提示错误信息,拒绝 Promiseuni.showToast({title: message || '请求失败',icon: 'none'});reject(new Error(message || '请求失败'));}},fail: (err) => {// 5. 统一处理网络错误uni.showToast({title: '网络错误,请稍后重试',icon: 'none'});reject(err);}});});
};// 6. 暴露常用请求方法(GET/POST),简化调用
export default {get(url, data) {return request({ url, method: 'GET', data });},post(url, data) {return request({ url, method: 'POST', data });},put(url, data) {return request({ url, method: 'PUT', data });},delete(url, data) {return request({ url, method: 'DELETE', data });}
};
3. 封装后如何使用?
在页面或组件中引入工具,调用方式极大简化:
// 在页面中引入请求工具
import request from '@/utils/request';export default {data() {return {userList: []};},onLoad() {// 调用 GET 方法获取用户列表this.getUserList();},methods: {async getUserList() {try {// 链式调用:直接获取后端返回的核心数据(无需再处理 code)const data = await request.get('/user/list', {page: 1,size: 10});// 业务处理this.userList = data;} catch (err) {// 错误处理(可选,工具已统一提示)console.error('获取用户列表失败', err);}},async doLogin() {try {// 调用 POST 方法提交登录数据const data = await request.post('/user/login', {username: 'test123',password: '123456'});// 登录成功:存储 Token(工具后续会自动携带)uni.setStorageSync('token', data.token);uni.switchTab({ url: '/pages/index/index' });} catch (err) {// 无需额外提示(工具已处理)}}}
};
三、关键问题解决:跨域、Token 与超时
在 uni-app 与后端交互过程中,跨域、Token 管理、超时处理是最常见的问题,下面逐一给出解决方案。
1. 跨域问题:仅存在于 H5 端
跨域是浏览器的安全策略,仅在 H5 端会出现(App、小程序端不限制跨域)。解决方式有两种:
方式 1:后端配置 CORS(推荐)
让后端在响应头中添加允许跨域的配置,例如(以 Node.js Express 为例):
// 后端代码:允许所有域名跨域(生产环境需指定具体域名)
app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', '*');res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');next();
});
方式 2:uni-app 配置代理(开发环境临时方案)
在 manifest.json
的 H5 配置中添加代理,将请求转发到后端地址,避免跨域:
// manifest.json -> "h5" 节点
"h5": {"devServer": {"proxy": {"/api": { // 匹配前端请求的 /api 前缀"target": "https://dev.api.example.com", // 后端真实地址"changeOrigin": true, // 开启跨域"pathRewrite": { // 重写路径(可选)"^/api": "" // 如前端请求 /api/user/list,实际转发到 https://dev.api.example.com/user/list}}}}
}
2. Token 管理:身份验证的核心
Token 是后端识别用户身份的凭证,通常在登录后获取,后续请求需携带。除了在封装工具中自动携带 Token,还需注意以下几点:
-
Token 存储:使用
uni.setStorageSync('token', token)
存储(同步),或uni.setStorage
(异步); -
Token 过期处理:在请求工具的
success
回调中拦截code: 401
(Token 过期),清除本地 Token 并跳转到登录页; -
Token 刷新:复杂场景下,可通过 “刷新 Token” 接口获取新 Token(需存储刷新 Token),避免用户重新登录。
3. 超时处理:避免请求无限等待
在 uni.request()
中添加 timeout
参数(单位:毫秒),设置请求超时时间,超时后会触发 fail
回调:
// 在封装工具的 config 中添加超时配置
const config = {// ...其他参数timeout: 10000, // 10秒超时
};
四、高级技巧:请求拦截与响应拦截
如果需要更灵活的请求控制(如添加加载动画、日志打印),可以在封装工具中增加 “请求拦截” 和 “响应拦截” 逻辑。
1. 请求拦截:发起请求前的处理
在请求发送前,可添加加载动画(如 uni.showLoading
)、打印请求日志等:
// 在 request 函数中,发起请求前添加拦截
const request = (options) => {// ...基础配置// 请求拦截:显示加载动画uni.showLoading({title: '加载中...',mask: true // 防止用户点击其他区域});return new Promise((resolve, reject) => {uni.request({...config,success: (res) => {// ...成功处理},fail: (err) => {// ...失败处理},complete: () => {// 无论成功/失败,都关闭加载动画uni.hideLoading();}});});
};
2. 响应拦截:获取响应后的统一处理
除了之前的错误拦截,还可添加日志打印(如记录请求耗时、返回数据):
// 在 success 回调中添加响应拦截
success: (res) => {// 打印响应日志(开发环境)if (process.env.NODE_ENV === 'development') {console.log(`[响应] ${config.url}:`, res.data);}// ...后续状态码处理
}
五、总结
uni-app 与后端的交互核心是 uni.request()
方法,通过封装工具可以大幅提升开发效率,统一处理请求逻辑。本文从基础用法到实战优化,覆盖了请求封装、跨域解决、Token 管理、高级拦截等关键知识点,掌握这些内容后,你可以轻松应对大多数业务场景。
最后提醒:实际开发中,需与后端明确接口文档(如请求方法、参数格式、返回状态码),避免因接口不统一导致的问题。如果需要处理更复杂的场景(如文件上传、WebSocket),可进一步学习 uni-app 的 uni.uploadFile()
和 uni.connectSocket()
方法。