mi-assessment/uniapp/utils/upload.js
zpc 4bba7f8e53 fix(upload): 改回PUT预签名URL方式,前端用readFile+uni.request PUT上传
- 后端恢复PUT预签名URL生成,移除POST Object的policy/signature逻辑
- 前端改用uni.getFileSystemManager().readFile读取二进制数据
- 再通过uni.request PUT方式直传COS(uni.uploadFile只支持POST)
- 参考验证过的CosUploadService实现
2026-02-20 23:46:01 +08:00

84 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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
}