1. uni.request网络请求
1.1 基础请求
// 基本GET请求
uni.request({
url: 'https://api.example.com/users',
method: 'GET',
success: (res) => {
console.log('请求成功:', res.data)
},
fail: (err) => {
console.error('请求失败:', err)
},
complete: () => {
console.log('请求完成')
}
})
// 基本POST请求
uni.request({
url: 'https://api.example.com/users',
method: 'POST',
data: {
name: '张三',
email: 'zhangsan@example.com'
},
header: {
'Content-Type': 'application/json'
},
success: (res) => {
console.log('创建成功:', res.data)
},
fail: (err) => {
console.error('创建失败:', err)
}
})
// Promise方式
function requestData(url, options = {}) {
return new Promise((resolve, reject) => {
uni.request({
url,
...options,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data)
} else {
reject(new Error(`HTTP ${res.statusCode}: ${res.errMsg}`))
}
},
fail: (err) => {
reject(new Error(err.errMsg || '网络请求失败'))
}
})
})
}
// 使用async/await
async function fetchUserData() {
try {
const userData = await requestData('https://api.example.com/user/123')
console.log('用户数据:', userData)
return userData
} catch (error) {
console.error('获取用户数据失败:', error)
throw error
}
}
1.2 请求拦截器
// utils/request.js
class RequestInterceptor {
constructor() {
this.requestQueue = []
this.isRefreshing = false
this.baseURL = 'https://api.example.com'
this.timeout = 10000
}
// 请求拦截
interceptRequest(config) {
// 添加基础URL
if (config.url && !config.url.startsWith('http')) {
config.url = this.baseURL + config.url
}
// 添加认证token
const token = uni.getStorageSync('token')
if (token) {
config.header = {
...config.header,
'Authorization': `Bearer ${token}`
}
}
// 添加公共请求头
config.header = {
'Content-Type': 'application/json',
'Accept': 'application/json',
...config.header
}
// 设置超时时间
config.timeout = config.timeout || this.timeout
console.log('请求拦截:', config)
return config
}
// 响应拦截
interceptResponse(response, config) {
console.log('响应拦截:', response)
// 处理HTTP状态码
if (response.statusCode >= 200 && response.statusCode < 300) {
// 处理业务状态码
const { code, data, message } = response.data
if (code === 200 || code === 0) {
return Promise.resolve(data)
} else if (code === 401) {
// token过期,尝试刷新
return this.handleTokenExpired(config)
} else {
return Promise.reject(new Error(message || '请求失败'))
}
} else {
return Promise.reject(new Error(`HTTP ${response.statusCode}`))
}
}
// 处理token过期
async handleTokenExpired(originalConfig) {
if (this.isRefreshing) {
// 如果正在刷新token,将请求加入队列
return new Promise((resolve, reject) => {
this.requestQueue.push({ resolve, reject, config: originalConfig })
})
}
this.isRefreshing = true
try {
const refreshToken = uni.getStorageSync('refreshToken')
if (!refreshToken) {
throw new Error('无刷新token')
}
// 刷新token
const response = await this.refreshTokenRequest(refreshToken)
const { token, refreshToken: newRefreshToken } = response
// 保存新token
uni.setStorageSync('token', token)
uni.setStorageSync('refreshToken', newRefreshToken)
// 重试原始请求
const retryResponse = await this.request(originalConfig)
// 处理队列中的请求
this.requestQueue.forEach(({ resolve, config }) => {
resolve(this.request(config))
})
this.requestQueue = []
return retryResponse
} catch (error) {
// 刷新失败,清除token并跳转登录
uni.removeStorageSync('token')
uni.removeStorageSync('refreshToken')
// 处理队列中的请求
this.requestQueue.forEach(({ reject }) => {
reject(new Error('登录已过期,请重新登录'))
})
this.requestQueue = []
// 跳转登录页
uni.reLaunch({
url: '/pages/login/login'
})
throw error
} finally {
this.isRefreshing = false
}
}
// 刷新token请求
refreshTokenRequest(refreshToken) {
return new Promise((resolve, reject) => {
uni.request({
url: this.baseURL + '/auth/refresh',
method: 'POST',
data: { refreshToken },
success: (res) => {
if (res.statusCode === 200 && res.data.code === 200) {
resolve(res.data.data)
} else {
reject(new Error('刷新token失败'))
}
},
fail: reject
})
})
}
// 主请求方法
request(config) {
return new Promise((resolve, reject) => {
// 请求拦截
const interceptedConfig = this.interceptRequest(config)
uni.request({
...interceptedConfig,
success: (response) => {
// 响应拦截
this.interceptResponse(response, config)
.then(resolve)
.catch(reject)
},
fail: (error) => {
console.error('网络请求失败:', error)
reject(new Error(error.errMsg || '网络连接失败'))
}
})
})
}
// 便捷方法
get(url, params = {}, config = {}) {
return this.request({
url,
method: 'GET',
data: params,
...config
})
}
post(url, data = {}, config = {}) {
return this.request({
url,
method: 'POST',
data,
...config
})
}
put(url, data = {}, config = {}) {
return this.request({
url,
method: 'PUT',
data,
...config
})
}
delete(url, config = {}) {
return this.request({
url,
method: 'DELETE',
...config
})
}
}
// 创建请求实例
const request = new RequestInterceptor()
export default request
1.3 API管理
// api/index.js
import request from '@/utils/request.js'
// 用户相关API
export const userAPI = {
// 用户登录
login(credentials) {
return request.post('/auth/login', credentials)
},
// 用户注册
register(userData) {
return request.post('/auth/register', userData)
},
// 获取用户信息
getUserInfo(userId) {
return request.get(`/users/${userId}`)
},
// 更新用户信息
updateUserInfo(userId, userData) {
return request.put(`/users/${userId}`, userData)
},
// 上传头像
uploadAvatar(file) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: request.baseURL + '/users/avatar',
filePath: file.path,
name: 'avatar',
header: {
'Authorization': `Bearer ${uni.getStorageSync('token')}`
},
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.code === 200) {
resolve(data.data)
} else {
reject(new Error(data.message))
}
} catch (error) {
reject(new Error('响应解析失败'))
}
},
fail: reject
})
})
},
// 修改密码
changePassword(passwordData) {
return request.post('/users/change-password', passwordData)
}
}
// 产品相关API
export const productAPI = {
// 获取产品列表
getProducts(params = {}) {
return request.get('/products', params)
},
// 获取产品详情
getProductDetail(productId) {
return request.get(`/products/${productId}`)
},
// 搜索产品
searchProducts(keyword, filters = {}) {
return request.get('/products/search', {
keyword,
...filters
})
},
// 获取产品分类
getCategories() {
return request.get('/products/categories')
},
// 获取热门产品
getHotProducts(limit = 10) {
return request.get('/products/hot', { limit })
}
}
// 订单相关API
export const orderAPI = {
// 创建订单
createOrder(orderData) {
return request.post('/orders', orderData)
},
// 获取订单列表
getOrders(params = {}) {
return request.get('/orders', params)
},
// 获取订单详情
getOrderDetail(orderId) {
return request.get(`/orders/${orderId}`)
},
// 取消订单
cancelOrder(orderId, reason) {
return request.post(`/orders/${orderId}/cancel`, { reason })
},
// 确认收货
confirmOrder(orderId) {
return request.post(`/orders/${orderId}/confirm`)
},
// 申请退款
requestRefund(orderId, refundData) {
return request.post(`/orders/${orderId}/refund`, refundData)
}
}
// 地址相关API
export const addressAPI = {
// 获取地址列表
getAddresses() {
return request.get('/addresses')
},
// 添加地址
addAddress(addressData) {
return request.post('/addresses', addressData)
},
// 更新地址
updateAddress(addressId, addressData) {
return request.put(`/addresses/${addressId}`, addressData)
},
// 删除地址
deleteAddress(addressId) {
return request.delete(`/addresses/${addressId}`)
},
// 设置默认地址
setDefaultAddress(addressId) {
return request.post(`/addresses/${addressId}/default`)
}
}
// 支付相关API
export const paymentAPI = {
// 创建支付订单
createPayment(paymentData) {
return request.post('/payments', paymentData)
},
// 查询支付状态
getPaymentStatus(paymentId) {
return request.get(`/payments/${paymentId}/status`)
},
// 获取支付方式
getPaymentMethods() {
return request.get('/payments/methods')
}
}
// 文件上传API
export const uploadAPI = {
// 上传单个文件
uploadFile(filePath, uploadPath = '/upload') {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: request.baseURL + uploadPath,
filePath,
name: 'file',
header: {
'Authorization': `Bearer ${uni.getStorageSync('token')}`
},
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.code === 200) {
resolve(data.data)
} else {
reject(new Error(data.message))
}
} catch (error) {
reject(new Error('响应解析失败'))
}
},
fail: reject
})
})
},
// 上传多个文件
async uploadMultipleFiles(filePaths, uploadPath = '/upload') {
const uploadPromises = filePaths.map(filePath =>
this.uploadFile(filePath, uploadPath)
)
try {
const results = await Promise.all(uploadPromises)
return results
} catch (error) {
console.error('批量上传失败:', error)
throw error
}
}
}
2. 文件上传与下载
2.1 图片上传
// utils/upload.js
class UploadManager {
constructor() {
this.maxFileSize = 5 * 1024 * 1024 // 5MB
this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
this.uploadURL = 'https://api.example.com/upload'
}
// 选择并上传图片
async chooseAndUploadImage(options = {}) {
try {
// 选择图片
const chooseResult = await this.chooseImage(options)
// 压缩图片
const compressedFiles = await this.compressImages(chooseResult.tempFiles)
// 上传图片
const uploadResults = await this.uploadImages(compressedFiles)
return uploadResults
} catch (error) {
console.error('图片上传失败:', error)
throw error
}
}
// 选择图片
chooseImage(options = {}) {
return new Promise((resolve, reject) => {
uni.chooseImage({
count: options.count || 1,
sizeType: options.sizeType || ['compressed'],
sourceType: options.sourceType || ['album', 'camera'],
success: resolve,
fail: reject
})
})
}
// 压缩图片
async compressImages(files) {
const compressPromises = files.map(file => this.compressImage(file))
return Promise.all(compressPromises)
}
// 压缩单张图片
compressImage(file) {
return new Promise((resolve, reject) => {
// 检查文件大小
if (file.size > this.maxFileSize) {
uni.compressImage({
src: file.path,
quality: 80,
success: (res) => {
resolve({
...file,
path: res.tempFilePath,
size: res.size || file.size
})
},
fail: () => {
// 压缩失败,使用原文件
resolve(file)
}
})
} else {
resolve(file)
}
})
}
// 批量上传图片
async uploadImages(files) {
const uploadPromises = files.map(file => this.uploadSingleImage(file))
try {
const results = await Promise.all(uploadPromises)
return results
} catch (error) {
console.error('批量上传失败:', error)
throw error
}
}
// 上传单张图片
uploadSingleImage(file) {
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: this.uploadURL,
filePath: file.path,
name: 'image',
formData: {
type: 'image',
timestamp: Date.now()
},
header: {
'Authorization': `Bearer ${uni.getStorageSync('token')}`
},
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.code === 200) {
resolve({
url: data.data.url,
filename: data.data.filename,
size: file.size,
originalFile: file
})
} else {
reject(new Error(data.message || '上传失败'))
}
} catch (error) {
reject(new Error('响应解析失败'))
}
},
fail: reject
})
// 监听上传进度
uploadTask.onProgressUpdate((res) => {
console.log('上传进度:', res.progress + '%')
// 可以通过事件或回调通知UI更新进度
uni.$emit('uploadProgress', {
filename: file.name,
progress: res.progress
})
})
})
}
// 预览图片
previewImages(urls, current = 0) {
uni.previewImage({
urls,
current: urls[current]
})
}
// 保存图片到相册
async saveImageToPhotosAlbum(url) {
try {
// 先下载图片
const downloadResult = await this.downloadFile(url)
// 保存到相册
await new Promise((resolve, reject) => {
uni.saveImageToPhotosAlbum({
filePath: downloadResult.tempFilePath,
success: resolve,
fail: reject
})
})
uni.showToast({
title: '保存成功',
icon: 'success'
})
} catch (error) {
console.error('保存图片失败:', error)
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
}
// 下载文件
downloadFile(url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url,
success: resolve,
fail: reject
})
})
}
}
// 创建上传管理实例
const uploadManager = new UploadManager()
export default uploadManager
2.2 文件下载
// utils/download.js
class DownloadManager {
constructor() {
this.downloadQueue = []
this.maxConcurrent = 3
this.activeDownloads = 0
}
// 下载文件
async downloadFile(url, options = {}) {
return new Promise((resolve, reject) => {
const downloadTask = uni.downloadFile({
url,
header: options.header || {},
success: (res) => {
if (res.statusCode === 200) {
resolve({
tempFilePath: res.tempFilePath,
statusCode: res.statusCode,
url
})
} else {
reject(new Error(`下载失败: HTTP ${res.statusCode}`))
}
},
fail: reject
})
// 监听下载进度
if (options.onProgress) {
downloadTask.onProgressUpdate(options.onProgress)
}
// 支持取消下载
if (options.onCancel) {
options.onCancel(() => {
downloadTask.abort()
})
}
})
}
// 批量下载
async downloadMultipleFiles(urls, options = {}) {
const downloadPromises = urls.map(url =>
this.downloadWithQueue(url, options)
)
try {
const results = await Promise.all(downloadPromises)
return results
} catch (error) {
console.error('批量下载失败:', error)
throw error
}
}
// 队列下载(控制并发数)
async downloadWithQueue(url, options = {}) {
return new Promise((resolve, reject) => {
this.downloadQueue.push({
url,
options,
resolve,
reject
})
this.processQueue()
})
}
// 处理下载队列
async processQueue() {
if (this.activeDownloads >= this.maxConcurrent || this.downloadQueue.length === 0) {
return
}
const { url, options, resolve, reject } = this.downloadQueue.shift()
this.activeDownloads++
try {
const result = await this.downloadFile(url, options)
resolve(result)
} catch (error) {
reject(error)
} finally {
this.activeDownloads--
this.processQueue() // 处理下一个
}
}
// 下载并保存文件
async downloadAndSave(url, filename, options = {}) {
try {
// 下载文件
const downloadResult = await this.downloadFile(url, options)
// 保存文件
const saveResult = await this.saveFile(downloadResult.tempFilePath, filename)
uni.showToast({
title: '下载完成',
icon: 'success'
})
return saveResult
} catch (error) {
console.error('下载保存失败:', error)
uni.showToast({
title: '下载失败',
icon: 'none'
})
throw error
}
}
// 保存文件
saveFile(tempFilePath, filename) {
return new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath,
success: (res) => {
resolve({
savedFilePath: res.savedFilePath,
filename
})
},
fail: reject
})
})
}
// 获取已保存的文件列表
getSavedFileList() {
return new Promise((resolve, reject) => {
uni.getSavedFileList({
success: resolve,
fail: reject
})
})
}
// 删除已保存的文件
removeSavedFile(filePath) {
return new Promise((resolve, reject) => {
uni.removeSavedFile({
filePath,
success: resolve,
fail: reject
})
})
}
// 获取文件信息
getFileInfo(filePath) {
return new Promise((resolve, reject) => {
uni.getFileInfo({
filePath,
success: resolve,
fail: reject
})
})
}
}
// 创建下载管理实例
const downloadManager = new DownloadManager()
export default downloadManager
3. WebSocket实时通信
3.1 WebSocket封装
// utils/websocket.js
class WebSocketManager {
constructor(url, options = {}) {
this.url = url
this.options = {
reconnectInterval: 5000,
maxReconnectAttempts: 5,
heartbeatInterval: 30000,
...options
}
this.ws = null
this.isConnected = false
this.reconnectAttempts = 0
this.heartbeatTimer = null
this.reconnectTimer = null
this.eventListeners = {
open: [],
message: [],
close: [],
error: []
}
this.messageQueue = []
}
// 连接WebSocket
connect() {
try {
this.ws = uni.connectSocket({
url: this.url,
header: this.options.header || {},
protocols: this.options.protocols || []
})
this.setupEventListeners()
} catch (error) {
console.error('WebSocket连接失败:', error)
this.handleError(error)
}
}
// 设置事件监听
setupEventListeners() {
// 连接打开
this.ws.onOpen(() => {
console.log('WebSocket连接已打开')
this.isConnected = true
this.reconnectAttempts = 0
// 发送队列中的消息
this.flushMessageQueue()
// 开始心跳
this.startHeartbeat()
// 触发open事件
this.emit('open')
})
// 接收消息
this.ws.onMessage((res) => {
try {
const data = JSON.parse(res.data)
console.log('收到WebSocket消息:', data)
// 处理心跳响应
if (data.type === 'pong') {
return
}
// 触发message事件
this.emit('message', data)
} catch (error) {
console.error('消息解析失败:', error)
this.emit('message', res.data)
}
})
// 连接关闭
this.ws.onClose((res) => {
console.log('WebSocket连接已关闭:', res)
this.isConnected = false
// 停止心跳
this.stopHeartbeat()
// 触发close事件
this.emit('close', res)
// 尝试重连
if (res.code !== 1000) { // 非正常关闭
this.attemptReconnect()
}
})
// 连接错误
this.ws.onError((error) => {
console.error('WebSocket错误:', error)
this.handleError(error)
})
}
// 发送消息
send(data) {
const message = typeof data === 'string' ? data : JSON.stringify(data)
if (this.isConnected) {
this.ws.send({
data: message,
success: () => {
console.log('消息发送成功:', message)
},
fail: (error) => {
console.error('消息发送失败:', error)
// 将失败的消息加入队列
this.messageQueue.push(message)
}
})
} else {
// 连接未建立,将消息加入队列
this.messageQueue.push(message)
console.log('连接未建立,消息已加入队列')
}
}
// 发送队列中的消息
flushMessageQueue() {
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift()
this.send(message)
}
}
// 关闭连接
close(code = 1000, reason = '正常关闭') {
if (this.ws) {
this.ws.close({
code,
reason
})
}
this.stopHeartbeat()
this.stopReconnect()
}
// 开始心跳
startHeartbeat() {
this.heartbeatTimer = setInterval(() => {
if (this.isConnected) {
this.send({ type: 'ping', timestamp: Date.now() })
}
}, this.options.heartbeatInterval)
}
// 停止心跳
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer)
this.heartbeatTimer = null
}
}
// 尝试重连
attemptReconnect() {
if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
console.error('达到最大重连次数,停止重连')
return
}
this.reconnectAttempts++
console.log(`尝试第${this.reconnectAttempts}次重连...`)
this.reconnectTimer = setTimeout(() => {
this.connect()
}, this.options.reconnectInterval)
}
// 停止重连
stopReconnect() {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer)
this.reconnectTimer = null
}
}
// 处理错误
handleError(error) {
this.emit('error', error)
}
// 添加事件监听
on(event, callback) {
if (this.eventListeners[event]) {
this.eventListeners[event].push(callback)
}
}
// 移除事件监听
off(event, callback) {
if (this.eventListeners[event]) {
const index = this.eventListeners[event].indexOf(callback)
if (index > -1) {
this.eventListeners[event].splice(index, 1)
}
}
}
// 触发事件
emit(event, data) {
if (this.eventListeners[event]) {
this.eventListeners[event].forEach(callback => {
try {
callback(data)
} catch (error) {
console.error('事件回调执行失败:', error)
}
})
}
}
// 获取连接状态
getReadyState() {
return this.isConnected ? 1 : 0
}
}
export default WebSocketManager
3.2 聊天应用示例
// utils/chat.js
import WebSocketManager from './websocket.js'
class ChatManager {
constructor() {
this.ws = null
this.currentRoom = null
this.userId = null
this.messageHandlers = new Map()
this.init()
}
// 初始化
init() {
this.userId = uni.getStorageSync('userId')
if (this.userId) {
this.connect()
}
}
// 连接聊天服务器
connect() {
const token = uni.getStorageSync('token')
const wsUrl = `wss://chat.example.com/ws?token=${token}&userId=${this.userId}`
this.ws = new WebSocketManager(wsUrl, {
reconnectInterval: 3000,
maxReconnectAttempts: 10,
heartbeatInterval: 25000
})
this.setupEventHandlers()
this.ws.connect()
}
// 设置事件处理
setupEventHandlers() {
// 连接成功
this.ws.on('open', () => {
console.log('聊天服务连接成功')
uni.$emit('chatConnected')
})
// 接收消息
this.ws.on('message', (data) => {
this.handleMessage(data)
})
// 连接关闭
this.ws.on('close', () => {
console.log('聊天服务连接关闭')
uni.$emit('chatDisconnected')
})
// 连接错误
this.ws.on('error', (error) => {
console.error('聊天服务连接错误:', error)
uni.$emit('chatError', error)
})
}
// 处理接收到的消息
handleMessage(data) {
const { type, payload } = data
switch (type) {
case 'message':
this.handleChatMessage(payload)
break
case 'userJoined':
this.handleUserJoined(payload)
break
case 'userLeft':
this.handleUserLeft(payload)
break
case 'typing':
this.handleTyping(payload)
break
case 'messageRead':
this.handleMessageRead(payload)
break
default:
console.log('未知消息类型:', type, payload)
}
}
// 处理聊天消息
handleChatMessage(message) {
console.log('收到聊天消息:', message)
// 保存消息到本地
this.saveMessageToLocal(message)
// 通知UI更新
uni.$emit('newMessage', message)
// 如果不是当前房间的消息,显示通知
if (message.roomId !== this.currentRoom) {
this.showMessageNotification(message)
}
}
// 处理用户加入
handleUserJoined(data) {
console.log('用户加入:', data)
uni.$emit('userJoined', data)
}
// 处理用户离开
handleUserLeft(data) {
console.log('用户离开:', data)
uni.$emit('userLeft', data)
}
// 处理正在输入
handleTyping(data) {
uni.$emit('userTyping', data)
}
// 处理消息已读
handleMessageRead(data) {
uni.$emit('messageRead', data)
}
// 发送聊天消息
sendMessage(roomId, content, type = 'text') {
const message = {
type: 'message',
payload: {
id: this.generateMessageId(),
roomId,
senderId: this.userId,
content,
messageType: type,
timestamp: Date.now()
}
}
this.ws.send(message)
// 保存到本地(发送状态)
this.saveMessageToLocal({
...message.payload,
status: 'sending'
})
return message.payload.id
}
// 发送图片消息
async sendImageMessage(roomId, imagePath) {
try {
// 上传图片
const uploadResult = await uploadManager.uploadSingleImage({ path: imagePath })
// 发送图片消息
return this.sendMessage(roomId, {
url: uploadResult.url,
width: uploadResult.width || 0,
height: uploadResult.height || 0
}, 'image')
} catch (error) {
console.error('发送图片消息失败:', error)
throw error
}
}
// 加入房间
joinRoom(roomId) {
this.currentRoom = roomId
this.ws.send({
type: 'joinRoom',
payload: { roomId }
})
}
// 离开房间
leaveRoom(roomId) {
this.ws.send({
type: 'leaveRoom',
payload: { roomId }
})
if (this.currentRoom === roomId) {
this.currentRoom = null
}
}
// 发送正在输入状态
sendTyping(roomId, isTyping = true) {
this.ws.send({
type: 'typing',
payload: {
roomId,
userId: this.userId,
isTyping
}
})
}
// 标记消息为已读
markMessageAsRead(messageId, roomId) {
this.ws.send({
type: 'markAsRead',
payload: {
messageId,
roomId,
userId: this.userId
}
})
}
// 保存消息到本地
saveMessageToLocal(message) {
const messages = uni.getStorageSync(`messages_${message.roomId}`) || []
messages.push(message)
// 只保留最近1000条消息
if (messages.length > 1000) {
messages.splice(0, messages.length - 1000)
}
uni.setStorageSync(`messages_${message.roomId}`, messages)
}
// 获取本地消息
getLocalMessages(roomId) {
return uni.getStorageSync(`messages_${roomId}`) || []
}
// 显示消息通知
showMessageNotification(message) {
// 这里可以根据平台显示不同的通知
uni.showToast({
title: `${message.senderName}: ${message.content}`,
icon: 'none',
duration: 2000
})
}
// 生成消息ID
generateMessageId() {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}
// 断开连接
disconnect() {
if (this.ws) {
this.ws.close()
this.ws = null
}
this.currentRoom = null
}
// 获取连接状态
isConnected() {
return this.ws && this.ws.getReadyState() === 1
}
}
// 创建聊天管理实例
const chatManager = new ChatManager()
export default chatManager
4. 数据缓存策略
4.1 智能缓存
// utils/smartCache.js
class SmartCache {
constructor() {
this.cache = new Map()
this.cacheConfig = {
// 不同类型数据的缓存策略
user: { ttl: 30 * 60 * 1000, maxSize: 100 }, // 30分钟
product: { ttl: 10 * 60 * 1000, maxSize: 500 }, // 10分钟
order: { ttl: 5 * 60 * 1000, maxSize: 200 }, // 5分钟
default: { ttl: 15 * 60 * 1000, maxSize: 300 } // 15分钟
}
this.init()
}
// 初始化
init() {
// 从本地存储恢复缓存
this.loadFromStorage()
// 定期清理过期缓存
setInterval(() => {
this.cleanExpiredCache()
}, 5 * 60 * 1000) // 5分钟清理一次
}
// 设置缓存
set(key, data, type = 'default') {
const config = this.cacheConfig[type] || this.cacheConfig.default
const now = Date.now()
const cacheItem = {
data,
type,
timestamp: now,
expireTime: now + config.ttl,
accessCount: 0,
lastAccess: now
}
this.cache.set(key, cacheItem)
// 检查缓存大小
this.checkCacheSize(type)
// 保存到本地存储
this.saveToStorage()
}
// 获取缓存
get(key) {
const cacheItem = this.cache.get(key)
if (!cacheItem) {
return null
}
// 检查是否过期
if (Date.now() > cacheItem.expireTime) {
this.cache.delete(key)
this.saveToStorage()
return null
}
// 更新访问信息
cacheItem.accessCount++
cacheItem.lastAccess = Date.now()
return cacheItem.data
}
// 删除缓存
delete(key) {
const deleted = this.cache.delete(key)
if (deleted) {
this.saveToStorage()
}
return deleted
}
// 清空指定类型的缓存
clearByType(type) {
let cleared = 0
for (const [key, item] of this.cache.entries()) {
if (item.type === type) {
this.cache.delete(key)
cleared++
}
}
if (cleared > 0) {
this.saveToStorage()
}
return cleared
}
// 清空所有缓存
clear() {
this.cache.clear()
this.saveToStorage()
}
// 检查缓存大小
checkCacheSize(type) {
const config = this.cacheConfig[type] || this.cacheConfig.default
const typeItems = Array.from(this.cache.entries())
.filter(([key, item]) => item.type === type)
if (typeItems.length > config.maxSize) {
// 按最后访问时间排序,删除最旧的
typeItems.sort((a, b) => a[1].lastAccess - b[1].lastAccess)
const deleteCount = typeItems.length - config.maxSize
for (let i = 0; i < deleteCount; i++) {
this.cache.delete(typeItems[i][0])
}
}
}
// 清理过期缓存
cleanExpiredCache() {
const now = Date.now()
let cleaned = 0
for (const [key, item] of this.cache.entries()) {
if (now > item.expireTime) {
this.cache.delete(key)
cleaned++
}
}
if (cleaned > 0) {
console.log(`清理了${cleaned}个过期缓存`)
this.saveToStorage()
}
}
// 保存到本地存储
saveToStorage() {
try {
const cacheData = Array.from(this.cache.entries())
uni.setStorageSync('smart_cache', cacheData)
} catch (error) {
console.error('保存缓存到本地存储失败:', error)
}
}
// 从本地存储加载
loadFromStorage() {
try {
const cacheData = uni.getStorageSync('smart_cache')
if (cacheData && Array.isArray(cacheData)) {
this.cache = new Map(cacheData)
// 清理过期的缓存
this.cleanExpiredCache()
}
} catch (error) {
console.error('从本地存储加载缓存失败:', error)
}
}
// 获取缓存统计
getStats() {
const stats = {
total: this.cache.size,
byType: {},
memoryUsage: 0
}
for (const [key, item] of this.cache.entries()) {
// 按类型统计
if (!stats.byType[item.type]) {
stats.byType[item.type] = 0
}
stats.byType[item.type]++
// 估算内存使用
stats.memoryUsage += JSON.stringify(item).length
}
return stats
}
// 获取或设置缓存(如果不存在则执行函数)
async getOrSet(key, asyncFunction, type = 'default') {
// 先尝试从缓存获取
const cached = this.get(key)
if (cached !== null) {
return cached
}
try {
// 执行异步函数获取数据
const data = await asyncFunction()
// 缓存结果
this.set(key, data, type)
return data
} catch (error) {
console.error('获取数据失败:', error)
throw error
}
}
}
// 创建智能缓存实例
const smartCache = new SmartCache()
export default smartCache
5. 总结
网络请求与数据交互是UniApp应用的核心功能:
- uni.request:基础的网络请求API,支持多种HTTP方法
- 请求拦截器:统一处理请求头、认证、错误等
- API管理:模块化管理不同业务的API接口
- 文件上传下载:处理图片、文档等文件的上传下载
- WebSocket:实现实时通信功能
- 数据缓存:提升应用性能和用户体验
- 错误处理:完善的错误处理和重试机制
- 离线支持:处理网络异常情况下的数据同步