📚 课程概述
网络请求是现代应用开发的核心功能,用于与后端API进行数据交互。本课程将深入讲解UniApp的网络请求机制,包括uni.request、文件上传下载、请求封装、错误处理等,帮助你构建稳定可靠的数据交互系统。
学习目标:
掌握uni.request的基本用法和参数配置
理解RESTful API的设计原则和调用方法
学会封装网络请求模块
掌握错误处理和请求拦截
了解文件上传下载的实现方法
🌐 什么是网络请求?
网络请求的概念
网络请求是指客户端(前端应用)向服务器发送请求,获取或提交数据的过程。UniApp提供了统一的网络请求API,支持跨平台使用。
网络请求流程:
前端应用 → 发送请求 → 服务器处理 → 返回响应 → 前端处理数据
HTTP请求方法
GET :获取资源,参数在URL中
POST :创建资源,参数在请求体中
PUT :更新资源,参数在请求体中
DELETE :删除资源
PATCH :部分更新资源
📡 uni.request基础用法
基本请求
uni.request参数详解
参数
类型
必填
说明
url
String
是
请求的接口地址
data
Object/String
否
请求的参数
header
Object
否
请求头
method
String
否
HTTP请求方法
timeout
Number
否
超时时间,单位ms
dataType
String
否
返回的数据类型
responseType
String
否
响应的数据类型
success
Function
否
成功回调函数
fail
Function
否
失败回调函数
complete
Function
否
完成回调函数
🔐 RESTful API设计
RESTful规范
RESTful是一种API设计风格,使用HTTP方法表示操作类型,使用URL表示资源:
// 获取用户列表
GET /api/users
// 获取单个用户
GET /api/users/:id
// 创建用户
POST /api/users
// 更新用户
PUT /api/users/:id
// 删除用户
DELETE /api/users/:id
// 分页查询
GET /api/users?page=1&pageSize=10
// 条件查询
GET /api/users?status=active&role=admin
RESTful API封装
// api/user.js
import request from '@/utils/request'
export default {
// 获取用户列表
getList(params) {
return request({
url: '/users',
method: 'GET',
params
})
},
// 获取用户详情
getDetail(id) {
return request({
url: `/users/${id}`,
method: 'GET'
})
},
// 创建用户
create(data) {
return request({
url: '/users',
method: 'POST',
data
})
},
// 更新用户
update(id, data) {
return request({
url: `/users/${id}`,
method: 'PUT',
data
})
},
// 删除用户
delete(id) {
return request({
url: `/users/${id}`,
method: 'DELETE'
})
}
}
🛡️ 请求封装与拦截
创建请求封装
// utils/request.js
const baseURL = 'https://api.example.com'
function request(options) {
return new Promise((resolve, reject) => {
uni.request({
url: baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getToken(),
...options.header
},
timeout: options.timeout || 30000,
dataType: options.dataType || 'json',
success: (res) => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data)
} else {
handleError(res)
reject(res)
}
},
fail: (error) => {
handleError(error)
reject(error)
},
complete: options.complete
})
})
}
function getToken() {
return uni.getStorageSync('token') || ''
}
function handleError(error) {
console.error('请求错误:', error)
if (error.statusCode === 401) {
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none'
})
uni.reLaunch({
url: '/pages/login/login'
})
} else if (error.statusCode === 403) {
uni.showToast({
title: '没有权限',
icon: 'none'
})
} else if (error.statusCode === 404) {
uni.showToast({
title: '请求的资源不存在',
icon: 'none'
})
} else if (error.statusCode >= 500) {
uni.showToast({
title: '服务器错误',
icon: 'none'
})
} else {
uni.showToast({
title: '网络错误',
icon: 'none'
})
}
}
export default request
请求拦截器
// utils/request.js
const requestQueue = []
let isRefreshing = false
function request(options) {
return new Promise((resolve, reject) => {
// 请求拦截
const config = {
url: baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getToken(),
...options.header
},
timeout: options.timeout || 30000,
dataType: options.dataType || 'json',
success: (res) => {
// 响应拦截
if (res.statusCode >= 200 && res.statusCode < 300) {
if (res.data.code === 200) {
resolve(res.data.data)
} else if (res.data.code === 401) {
handleTokenExpired()
reject(res.data)
} else {
uni.showToast({
title: res.data.message || '请求失败',
icon: 'none'
})
reject(res.data)
}
} else {
handleError(res)
reject(res)
}
},
fail: (error) => {
handleError(error)
reject(error)
}
}
uni.request(config)
})
}
function handleTokenExpired() {
if (isRefreshing) {
return new Promise((resolve) => {
requestQueue.push({ resolve })
})
}
isRefreshing = true
refreshToken().then(token => {
uni.setStorageSync('token', token)
requestQueue.forEach(item => item.resolve())
requestQueue.length = 0
isRefreshing = false
}).catch(() => {
requestQueue.length = 0
isRefreshing = false
uni.reLaunch({
url: '/pages/login/login'
})
})
}
function refreshToken() {
return uni.request({
url: baseURL + '/auth/refresh',
method: 'POST',
data: {
refreshToken: uni.getStorageSync('refreshToken')
}
})
}
export default request
📤 文件上传
uni.uploadFile
export default {
data() {
return {
imageUrl: ''
}
},
methods: {
chooseImage() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths
this.uploadFile(tempFilePaths[0])
}
})
},
uploadFile(filePath) {
uni.showLoading({
title: '上传中...'
})
uni.uploadFile({
url: 'https://api.example.com/upload',
filePath: filePath,
name: 'file',
formData: {
'user': 'test'
},
header: {
'Authorization': 'Bearer ' + getToken()
},
success: (uploadFileRes) => {
const data = JSON.parse(uploadFileRes.data)
console.log('上传成功:', data)
this.imageUrl = data.url
uni.showToast({
title: '上传成功',
icon: 'success'
})
},
fail: (error) => {
console.error('上传失败:', error)
uni.showToast({
title: '上传失败',
icon: 'none'
})
},
complete: () => {
uni.hideLoading()
}
})
}
}
}
📥 文件下载
uni.downloadFile
export default {
methods: {
downloadFile(url) {
uni.showLoading({
title: '下载中...'
})
const downloadTask = uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
console.log('下载成功:', res.tempFilePath)
// 保存文件
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
console.log('保存成功:', saveRes.savedFilePath)
uni.showToast({
title: '下载成功',
icon: 'success'
})
}
})
}
},
fail: (error) => {
console.error('下载失败:', error)
uni.showToast({
title: '下载失败',
icon: 'none'
})
},
complete: () => {
uni.hideLoading()
}
})
// 监听下载进度
downloadTask.onProgressUpdate((res) => {
console.log('下载进度:', res.progress + '%')
console.log('已下载:', res.totalBytesWritten)
console.log('总大小:', res.totalBytesExpectedToWrite)
})
}
}
}
💡 最佳实践
性能优化建议:
使用请求缓存,减少重复请求
实现请求防抖,避免频繁请求
合理设置超时时间,避免长时间等待
使用CDN加速静态资源加载
压缩请求数据,减少传输量
常见问题:
跨域问题:配置服务器CORS或使用代理
请求超时:检查网络连接和服务器响应
token过期:实现自动刷新机制
重复请求:使用请求取消或防抖
🎯 实战案例:用户管理
{{ user.name }}
{{ user.email }}
编辑
删除
加载中...
🔮 下一步学习方向
掌握了网络请求后,下一课我们将深入学习数据存储,了解如何在本地存储和管理应用数据。