业务场景及实践遇到的问题
- 业务场景
- 微信小程序内,需要实现一个类似微博的图文列表,支持顶部新增图文,新增成功之后,列表立即加载新增的图文记录。
- 遇到的问题
- 微信小程序对应的服务端使用了
微信云托管
,所以选择使用云托管中的对象存储
服务来保存图片。 - 使用
wx.cloud.uploadFile
上传图片,图片上传成功后,image标签对应的src使用官方推荐的loadcos
转换方法来转换fileId得到用于公开访问的url,但是图片都不能正常展示出来。
javascript
function loadcos(url){
var res = url
if (url.indexOf('cloud://') === 0) {
var first = url.indexOf('.')
var end = url.indexOf('/', first)
res = 'https://' + url.slice(first + 1, end) + '.tcb.qcloud.la/' + url.slice(end + 1, url.length)
}
return res
}
module.exports={
loadcos:loadcos
}
在微信开发者工具中会看到有两次对应的图片网络请求:
-
第一个请求的域名是
tcb.qcloud.la
,而第二个请求的域名是cos.ap-shanghai.myqcloud.com
。 -
这表明可能存在两种不同的访问路径:
tcb.qcloud.la
是微信云存储的默认域名。cos.ap-shanghai.myqcloud.com
是腾讯云 COS 的 CDN 域名。
-
第一个请求返回
404
,第二个请求返回No content
分析可能的原因:tcb.qcloud.la
域名的url是loadcos
方法转换得到的,返回404,大概率是因为云存储有做读写分离,图片上传到写服务,但是还没同步到读服务;cos.ap-shanghai.myqcloud.com
域名的url请求应该是微信小程序内部实现的机制,在不能正确从云存储加载到图片时,再请求一遍存储对应区域的CDN,多做一次尝试,但是读取的还是云存储的读服务,所以还是不能正确获取图片文件。
解决方案
在图片上传到云端后需要立即展示的情况下。通过直接使用本地临时文件路径(tmpFilePath
)作为 <image>
的 src
属性值,可以绕过网络延迟和云存储同步的问题,从而实现图片的即时加载。
以下是详细分析:
为什么使用 tmpFilePath
能立即加载图片?
-
本地文件路径
tmpFilePath
是用户选择图片时生成的本地临时文件路径(例如:wx.chooseImage
返回的tempFilePaths
)。- 这个路径指向的是设备本地的文件,因此可以直接读取,无需等待网络传输或云存储同步。
-
避免网络延迟
- 上传图片到云端后,文件可能需要时间写入存储系统,并同步到 CDN。如果直接使用云端路径(如
fileID
或CDN URL
),可能会因为同步延迟导致图片无法立即加载。 - 使用
tmpFilePath
可以完全避免这些网络问题。
- 上传图片到云端后,文件可能需要时间写入存储系统,并同步到 CDN。如果直接使用云端路径(如
-
用户体验提升
- 用户在选择图片后,可以立即看到图片预览,而无需等待上传完成。这种即时反馈显著提升了用户体验。
代码示例
以下是一个完整的代码示例,展示如何在微信小程序中实现这一方案:
javascript
Page({
data: {
tempFilePath: '', // 用于存储本地临时文件路径
cloudFileURL: '', // 用于存储云端文件 URL
},
// 选择图片并显示临时文件
chooseImage() {
wx.chooseImage({
count: 1, // 允许选择一张图片
success: (res) => {
const tempFilePath = res.tempFilePaths[0]; // 获取临时文件路径
this.setData({
tempFilePath: tempFilePath, // 设置临时文件路径为图片 src
});
// 上传图片到云端
this.uploadImage(tempFilePath);
},
fail: (err) => {
console.error('选择图片失败:', err);
},
});
},
// 上传图片到云端
uploadImage(tempFilePath) {
wx.cloud.uploadFile({
cloudPath: `images/${Date.now()}.jpg`, // 云端存储路径
filePath: tempFilePath, // 本地临时文件路径
success: (uploadRes) => {
console.log('图片上传成功:', uploadRes.fileID);
// 获取云端文件的临时访问链接
wx.cloud.getTempFileURL({
fileList: [uploadRes.fileID],
success: (urlRes) => {
const cloudFileURL = urlRes.fileList[0].tempFileURL;
this.setData({
cloudFileURL: cloudFileURL, // 更新云端文件 URL
});
console.log('获取云端文件 URL 成功:', cloudFileURL);
},
fail: (err) => {
console.error('获取云端文件 URL 失败:', err);
},
});
},
fail: (err) => {
console.error('图片上传失败:', err);
},
});
},
});
WXML 示例
html
<view>
<!-- 显示图片 -->
<image
:src="cloudFileURL || tempFilePath"
mode="aspectFit"
style="width: 100%; height: 300px;">
</image>
<!-- 选择图片按钮 -->
<button bindtap="chooseImage">选择图片</button>
</view>
逻辑解释
-
选择图片
- 用户点击按钮触发
chooseImage
方法。 - 使用
wx.chooseImage
选择图片,获取临时文件路径tempFilePath
。 - 将
tempFilePath
设置为<image>
的src
,立即显示图片。
- 用户点击按钮触发
-
上传图片
- 同时调用
uploadImage
方法将图片上传到云端。 - 上传完成后,通过
wx.cloud.getTempFileURL
获取云端文件的临时访问链接。
- 同时调用
-
更新云端 URL
- 当云端文件 URL 可用时,更新
cloudFileURL
。 <image>
的src
会自动切换为云端 URL,确保图片持久化。
- 当云端文件 URL 可用时,更新
优点
- 即时显示:用户选择图片后,图片立即显示,无需等待上传完成。
- 无缝切换:当云端 URL 可用时,图片源会自动切换为云端地址,保证后续访问的稳定性。
- 减少延迟:避免了因网络延迟或云存储同步导致的图片加载失败。
注意事项
-
临时文件的有效期
tmpFilePath
是一个临时文件路径,通常只在当前页面或会话中有效。如果需要长期保存图片,必须上传到云端并使用云端 URL。
-
错误处理
- 如果上传失败,确保有相应的错误提示机制,并允许用户重新上传。
-
性能优化
- 如果图片较大,可以在上传前进行压缩(如使用
wx.compressImage
),以减少上传时间和流量消耗。
- 如果图片较大,可以在上传前进行压缩(如使用
总结
通过使用 tmpFilePath
作为图片的初始 src
,可以实现图片的即时加载,显著提升用户体验。同时,结合云端 URL 的动态切换,可以确保图片的持久化和长期可用性。这种方案适用于大多数需要快速预览图片的场景,是微信小程序开发中常用的最佳实践之一。