- 后端恢复PUT预签名URL生成,移除POST Object的policy/signature逻辑 - 前端改用uni.getFileSystemManager().readFile读取二进制数据 - 再通过uni.request PUT方式直传COS(uni.uploadFile只支持POST) - 参考验证过的CosUploadService实现
84 lines
2.7 KiB
JavaScript
84 lines
2.7 KiB
JavaScript
/**
|
||
* COS直传工具
|
||
* 通过PUT预签名URL将文件直传到腾讯云COS
|
||
* 使用 uni.getFileSystemManager().readFile 读取文件二进制数据
|
||
* 再通过 uni.request PUT 方式上传(uni.uploadFile 只支持 POST)
|
||
*/
|
||
|
||
import { getPresignedUploadUrl } from '@/api/user.js'
|
||
|
||
/**
|
||
* 选择图片并上传到COS
|
||
* @param {Object} [options] - 选项
|
||
* @param {number} [options.count=1] - 选择数量
|
||
* @param {string[]} [options.sourceType] - 来源类型
|
||
* @returns {Promise<string>} 上传后的文件URL
|
||
*/
|
||
export async function chooseAndUploadImage(options = {}) {
|
||
const { count = 1, sourceType = ['album', 'camera'] } = options
|
||
|
||
// 1. 选择图片
|
||
const chooseRes = await new Promise((resolve, reject) => {
|
||
uni.chooseImage({
|
||
count,
|
||
sizeType: ['compressed'],
|
||
sourceType,
|
||
success: resolve,
|
||
fail: (err) => {
|
||
if (err.errMsg && err.errMsg.includes('cancel')) {
|
||
reject(new Error('用户取消选择'))
|
||
} else {
|
||
reject(new Error('选择图片失败'))
|
||
}
|
||
}
|
||
})
|
||
})
|
||
|
||
const tempFilePath = chooseRes.tempFilePaths[0]
|
||
const fileName = tempFilePath.split('/').pop() || 'image.png'
|
||
|
||
// 判断文件类型
|
||
const ext = fileName.split('.').pop()?.toLowerCase() || 'png'
|
||
const mimeMap = { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif', webp: 'image/webp' }
|
||
const contentType = mimeMap[ext] || 'image/png'
|
||
|
||
// 2. 获取预签名URL
|
||
const presignedRes = await getPresignedUploadUrl(fileName, contentType)
|
||
if (!presignedRes || presignedRes.code !== 0 || !presignedRes.data) {
|
||
throw new Error(presignedRes?.message || '获取上传地址失败')
|
||
}
|
||
|
||
const { uploadUrl, fileUrl } = presignedRes.data
|
||
|
||
// 3. 读取文件二进制数据,然后用PUT方式上传到COS
|
||
await new Promise((resolve, reject) => {
|
||
uni.getFileSystemManager().readFile({
|
||
filePath: tempFilePath,
|
||
success: (readRes) => {
|
||
// 使用PUT方法上传二进制数据
|
||
uni.request({
|
||
url: uploadUrl,
|
||
method: 'PUT',
|
||
data: readRes.data,
|
||
header: {
|
||
'Content-Type': contentType
|
||
},
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
resolve(res)
|
||
} else {
|
||
console.error('COS上传失败:', res.statusCode, res.data)
|
||
reject(new Error(`上传失败,状态码: ${res.statusCode}`))
|
||
}
|
||
},
|
||
fail: (err) => reject(new Error('上传COS失败: ' + (err.errMsg || '网络错误')))
|
||
})
|
||
},
|
||
fail: (err) => reject(new Error('读取文件失败: ' + err.errMsg))
|
||
})
|
||
})
|
||
|
||
// 4. 返回文件访问URL
|
||
return fileUrl
|
||
}
|