惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
V2EX - 技术
V2EX - 技术
Hacker News: Ask HN
Hacker News: Ask HN
T
Tailwind CSS Blog
V
Visual Studio Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
月光博客
月光博客
H
Hacker News: Front Page
D
DataBreaches.Net
GbyAI
GbyAI
Recorded Future
Recorded Future
IT之家
IT之家
H
Heimdal Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Schneier on Security
Schneier on Security
P
Privacy International News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Security Affairs
博客园 - 三生石上(FineUI控件)
M
MIT News - Artificial intelligence
Google Online Security Blog
Google Online Security Blog
L
LINUX DO - 最新话题
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
L
LangChain Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
The Last Watchdog
The Last Watchdog
I
Intezer
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hacker News - Newest:
Hacker News - Newest: "LLM"
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
U
Unit 42
H
Help Net Security
Simon Willison's Weblog
Simon Willison's Weblog
Y
Y Combinator Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
T
Tenable Blog
TaoSecurity Blog
TaoSecurity Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
B
Blog
S
Security @ Cisco Blogs
A
About on SuperTechFans
V
V2EX
T
The Exploit Database - CXSecurity.com

吖远zzyの博客

记录一下豆包视频去水印的研究过程,以及fallback_api加密数据qAAB开头数据的解密。 | 吖远zzyの博客 解决华为开发者工具 DevEco Studio 登录跳转 localhost:10101 端口被阻止问题 | 吖远zzyの博客 微信小程序个人资质审核血泪史:踩坑,从反复被拒到神奇过审 | 吖远zzyの博客 如何实现公众号自动回复或做一个短视频无水印解析机器人? | 吖远zzyの博客 以后在手机上用 Termux 和 GitHub Actions 更新 Hexo 博客 | 吖远zzyの博客 必备!这款万能小程序能给抖音/豆包视频图集去除水印、还有有趣的测反应、玩成语模拟工具。 自制的一些免费API接口第二弹(获取QQ昵称、头像、抖音/豆包视频去水印等...) 告别原生导航栏:微信小程序自定义导航栏完美适配方案 在安卓手机上运行OpenClaw?当然可以,用Termux折腾OpenClaw安装QQ机器人的踩坑记录... | 吖远zzyの博客 个人开发工具之抖音直播录制工具:一款功能强大的Android直播录制应用 UniApp中Canvas绘图的易错点与踩坑指南 QQ频道机器人与UniApp开发:常见踩坑点与解决方案 UniApp中Canvas绘图不显示的常见问题与解决方案 Hexo博客实现随机文章功能的完整教程 QQ频道机器人Android客户端使用指南 | 吖远zzyの博客 安卓版QQ频道机器人APP客户端插件开发指南 | 吖远zzyの博客 2024年AI编程助手深度评测:哪款最适合你? uni-app地图定位踩坑记:地图功能和定位的那些坑 uni-app文件上传踩坑记:图片处理和上传全攻略 uni-app表单验证踩坑记:这些坑我替你踩过了 uni-app开发踩坑记录:新手必看的常见问题与解决方案 uni-app安全防护指南:构建可靠的跨端应用 uni-app性能优化指南:从加载到渲染的全方位提升 uni-app动画效果实战:从基础到高级的动画实现指南 uni-app组件开发实战:从基础到进阶的最佳实践 uni-app状态管理进阶:Vuex最佳实践与性能优化 uni-app路由与页面跳转:最佳实践与踩坑指南
uni-app网络请求与缓存策略:构建高效的数据层
吖远zzy · 2024-03-25 · via 吖远zzyの博客
  1. 1. 1. 网络请求封装
    1. 1.1. 1.1 基础请求类
    2. 1.2. 1.2 请求拦截器
  2. 2. 2. 数据缓存策略
    1. 2.1. 2.1 缓存管理类
    2. 2.2. 2.2 数据预加载
  3. 3. 3. 实际应用示例
    1. 3.1. 3.1 API封装
    2. 3.2. 3.2 数据预加载
  4. 4. 4. 最佳实践建议
  5. 5. 5. 总结

uni-app网络请求与缓存策略:构建高效的数据层 0 次阅读

网络请求和数据缓存是应用开发中的关键环节,本文将详细介绍如何在uni-app中构建高效可靠的数据层。

1. 网络请求封装

1.1 基础请求类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// utils/request.js
class Request {
constructor(options = {}) {
this.baseURL = options.baseURL || ''
this.timeout = options.timeout || 60000
this.header = options.header || {}
this.beforeRequest = options.beforeRequest
this.afterRequest = options.afterRequest
}

// 请求拦截
beforeRequest(config) {
// 添加token
const token = uni.getStorageSync('token')
if (token) {
config.header.Authorization = `Bearer ${token}`
}
return config
}

// 响应拦截
afterRequest(response) {
const { statusCode, data } = response
if (statusCode >= 200 && statusCode < 300) {
return data
}
return Promise.reject(response)
}

// 请求方法
request(options = {}) {
options.baseURL = options.baseURL || this.baseURL
options.timeout = options.timeout || this.timeout
options.header = { ...this.header, ...options.header }
options.method = options.method || 'GET'

// 请求拦截
if (this.beforeRequest) {
options = this.beforeRequest(options)
}

return new Promise((resolve, reject) => {
uni.request({
...options,
url: options.baseURL + options.url,
success: (res) => {
// 响应拦截
if (this.afterRequest) {
try {
const data = this.afterRequest(res)
resolve(data)
} catch (error) {
reject(error)
}
} else {
resolve(res.data)
}
},
fail: (err) => {
reject(err)
}
})
})
}

// 封装常用请求方法
get(url, data = {}, options = {}) {
return this.request({
url,
data,
method: 'GET',
...options
})
}

post(url, data = {}, options = {}) {
return this.request({
url,
data,
method: 'POST',
...options
})
}

put(url, data = {}, options = {}) {
return this.request({
url,
data,
method: 'PUT',
...options
})
}

delete(url, data = {}, options = {}) {
return this.request({
url,
data,
method: 'DELETE',
...options
})
}
}

export default new Request({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000,
header: {
'Content-Type': 'application/json'
}
})

1.2 请求拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// utils/interceptors.js
import store from '@/store'

// 请求队列
let requestQueue = []
// 是否正在刷新token
let isRefreshing = false

export const requestInterceptor = (config) => {
// 添加token
const token = uni.getStorageSync('token')
if (token) {
config.header.Authorization = `Bearer ${token}`
}
return config
}

export const responseInterceptor = async (response) => {
const { statusCode, data } = response

// token过期处理
if (statusCode === 401) {
// 将请求添加到队列
const retryRequest = new Promise((resolve) => {
requestQueue.push((token) => {
config.header.Authorization = `Bearer ${token}`
resolve(request.request(config))
})
})

// 是否正在刷新token
if (!isRefreshing) {
isRefreshing = true
try {
// 刷新token
const { token } = await store.dispatch('user/refreshToken')
// 重试队列中的请求
requestQueue.forEach(callback => callback(token))
requestQueue = []
return request.request(config)
} catch (error) {
// 刷新token失败,跳转登录页
store.dispatch('user/logout')
uni.navigateTo({
url: '/pages/login/index'
})
return Promise.reject(error)
} finally {
isRefreshing = false
}
}
return retryRequest
}

return data
}

2. 数据缓存策略

2.1 缓存管理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// utils/cache.js
class Cache {
constructor(options = {}) {
this.prefix = options.prefix || 'app_'
this.expire = options.expire || 0
this.isEncrypt = options.isEncrypt || false
}

// 设置缓存
setItem(key, value, expire = 0) {
const data = {
value,
time: Date.now(),
expire: expire || this.expire
}

// 加密处理
const stringData = this.isEncrypt
? this.encrypt(JSON.stringify(data))
: JSON.stringify(data)

try {
uni.setStorageSync(this.prefix + key, stringData)
} catch (error) {
console.error('缓存设置失败:', error)
}
}

// 获取缓存
getItem(key) {
try {
const data = uni.getStorageSync(this.prefix + key)
if (!data) return null

// 解密处理
const storage = this.isEncrypt
? JSON.parse(this.decrypt(data))
: JSON.parse(data)

// 过期判断
if (storage.expire && Date.now() - storage.time > storage.expire * 1000) {
uni.removeStorageSync(this.prefix + key)
return null
}

return storage.value
} catch (error) {
console.error('缓存获取失败:', error)
return null
}
}

// 移除缓存
removeItem(key) {
try {
uni.removeStorageSync(this.prefix + key)
} catch (error) {
console.error('缓存移除失败:', error)
}
}

// 清空缓存
clear() {
try {
uni.clearStorageSync()
} catch (error) {
console.error('缓存清空失败:', error)
}
}

// 加密方法
encrypt(data) {
// 实现加密逻辑
return data
}

// 解密方法
decrypt(data) {
// 实现解密逻辑
return data
}
}

export default new Cache({
prefix: 'app_',
expire: 7 * 24 * 60 * 60, // 默认7天过期
isEncrypt: process.env.NODE_ENV === 'production' // 生产环境开启加密
})

2.2 数据预加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// utils/preload.js
import cache from './cache'
import request from './request'

class Preload {
constructor() {
this.tasks = new Map()
}

// 添加预加载任务
add(key, promiseCreator) {
if (!this.tasks.has(key)) {
const task = promiseCreator().then(data => {
cache.setItem(key, data)
return data
})
this.tasks.set(key, task)
}
return this.tasks.get(key)
}

// 获取预加载数据
async get(key, promiseCreator) {
// 优先从缓存获取
const cached = cache.getItem(key)
if (cached) return cached

// 其次从预加载任务获取
if (this.tasks.has(key)) {
return this.tasks.get(key)
}

// 最后实时加载
return this.add(key, promiseCreator)
}

// 清除预加载任务
clear() {
this.tasks.clear()
}
}

export default new Preload()

// 使用示例
const preload = new Preload()

// 预加载数据
preload.add('userInfo', () => {
return request.get('/api/user/info')
})

// 获取数据
const userInfo = await preload.get('userInfo', () => {
return request.get('/api/user/info')
})

3. 实际应用示例

3.1 API封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// api/user.js
import request from '@/utils/request'
import cache from '@/utils/cache'

export function login(data) {
return request.post('/api/login', data)
}

export function getUserInfo() {
return cache.remember('user_info', () => {
return request.get('/api/user/info')
}, 30 * 60) // 缓存30分钟
}

export function updateUserInfo(data) {
return request.put('/api/user/info', data).then(() => {
// 更新后清除缓存
cache.removeItem('user_info')
})
}

3.2 数据预加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// pages/index/index.vue
import preload from '@/utils/preload'

export default {
onLoad() {
// 预加载下一页数据
this.preloadNextPage()
},
methods: {
preloadNextPage() {
const nextPage = this.currentPage + 1
preload.add(`list_page_${nextPage}`, () => {
return request.get('/api/list', {
page: nextPage,
size: 10
})
})
},
async loadNextPage() {
const nextPage = this.currentPage + 1
const data = await preload.get(`list_page_${nextPage}`, () => {
return request.get('/api/list', {
page: nextPage,
size: 10
})
})
this.list.push(...data.list)
this.currentPage = nextPage
// 继续预加载下一页
this.preloadNextPage()
}
}
}

4. 最佳实践建议

  1. 统一封装请求方法
  2. 实现请求拦截和响应拦截
  3. 合理使用数据缓存
  4. 实现数据预加载
  5. 注意安全性处理

5. 总结

  1. 掌握请求封装技巧
  2. 实现数据缓存策略
  3. 优化数据加载体验
  4. 处理异常情况
  5. 保证数据安全性

如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力!