# COS POST 表单上传 - 完整修复版 ## ✅ 问题已修复 已修复 COS POST 表单上传的签名问题: - ✅ 添加了 `q-key-time` 字段 - ✅ 添加了 `q-sign-time` 字段 - ✅ Policy 中包含必需的签名条件 - ✅ 使用正确的 COS 签名算法 --- ## 📋 前端正确的上传代码 ### Vue 3 + Element Plus 完整示例 ```vue ``` --- ### 原生 JavaScript 示例 ```javascript async function uploadFileToCOS(file, userId) { try { // 1. 获取 POST 签名 const signResponse = await fetch('/user/oss/post-signature', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + localStorage.getItem('token') }, body: JSON.stringify({ fileName: file.name, userId: userId }) }); const signResult = await signResponse.json(); if (signResult.code !== 200) { throw new Error(signResult.message); } const data = signResult.data; // 2. 构造表单数据(COS 标准字段) const formData = new FormData(); const fileKey = data.dir + Date.now() + '_' + file.name; formData.append('key', fileKey); // 文件路径 formData.append('policy', data.policy); // Policy formData.append('q-sign-algorithm', data['q-sign-algorithm']); // 签名算法 formData.append('q-ak', data['q-ak']); // SecretId formData.append('q-key-time', data['q-key-time']); // KeyTime(必需) formData.append('q-signature', data['q-signature']); // 签名 formData.append('file', file); // 文件(必须最后) // 3. 上传到 COS const uploadResponse = await fetch(data.host, { method: 'POST', body: formData }); if (!uploadResponse.ok) { const errorText = await uploadResponse.text(); console.error('COS 返回错误:', errorText); throw new Error('上传失败: ' + uploadResponse.status); } // 4. 上传成功 const fileUrl = data.host + '/' + fileKey; console.log('上传成功,文件地址:', fileUrl); return fileUrl; } catch (error) { console.error('上传失败:', error); throw error; } } // 使用示例 document.getElementById('fileInput').addEventListener('change', async (e) => { const file = e.target.files[0]; if (file) { try { const fileUrl = await uploadFileToCOS(file, '123'); alert('上传成功: ' + fileUrl); } catch (error) { alert('上传失败: ' + error.message); } } }); ``` --- ## 📡 后端返回的签名数据 ```json { "code": 200, "message": "POST签名生成成功", "data": { "policy": "eyJleHBpcmF0aW9uIjoi...", "q-sign-algorithm": "sha1", "q-ak": "AKIDVY1HLBnDZhbHkz0mLhgT3TgePXHNErLC", "q-key-time": "1733472660;1733476260", "q-sign-time": "1733472660;1733476260", "q-signature": "7758dc9a832e9d301dca704cacbf9d9f8172abcd", "host": "https://oss-1818ai-user-img-1302947942.cos.ap-guangzhou.myqcloud.com", "dir": "user_img/", "fileName": "avatar.jpg", "fileType": "image", "maxFileSize": 10485760, "maxFileSizeMB": 10 } } ``` --- ## 🔑 必需的表单字段 前端提交表单时**必须包含**以下字段: | 字段名 | 说明 | 示例值 | |--------|------|--------| | `key` | 文件路径 | `user_img/1733472660_avatar.jpg` | | `policy` | Base64 编码的 Policy | `eyJleHBpcmF0aW9uIjoi...` | | `q-sign-algorithm` | 签名算法 | `sha1` | | `q-ak` | SecretId | `AKIDVY1HLBnDZhbHkz0mLhgT3TgePXHNErLC` | | `q-key-time` | 密钥有效时间 | `1733472660;1733476260` | | `q-signature` | 签名 | `7758dc9a832e9d301dca704cacbf9d9f8172abcd` | | `file` | 文件内容 | (二进制数据,必须最后) | --- ## ⚠️ 常见错误和解决方案 ### 1. SignatureDoesNotMatch - q-key-time is required **错误信息:** ```xml SignatureDoesNotMatch form field q-key-time is required,but not found or empty. ``` **原因:** 表单中缺少 `q-key-time` 字段 **解决:** 确保表单包含: ```javascript formData.append('q-key-time', data['q-key-time']); ``` --- ### 2. InvalidPolicyDocument - q-sign-time is required **错误信息:** ```xml InvalidPolicyDocument policy condition q-sign-time is required,but not found. ``` **原因:** Policy 中缺少 `q-sign-time` 条件 **解决:** 后端已修复,重新编译部署即可 --- ### 3. SignatureDoesNotMatch - 签名不匹配 **原因:** 签名计算错误或字段值不匹配 **解决:** 1. 确保 `q-key-time` 和 `q-sign-time` 的值相同 2. 确保 `key` 字段以 `dir` 开头 3. 确保所有字段值与后端返回的完全一致 --- ### 4. CORS 错误 **解决:** 在腾讯云 COS 控制台配置 CORS: - 来源:`*` 或具体域名 - 方法:`GET, POST, PUT, HEAD` - Allow-Headers:`*` --- ## 🧪 测试上传 ### 使用 curl 测试 ```bash # 1. 获取签名 curl -X POST http://localhost:8083/user/oss/post-signature \ -H "Content-Type: application/json" \ -d '{"userId":"123","fileName":"test.jpg"}' # 2. 使用返回的签名上传(替换实际值) curl -X POST "https://oss-1818ai-user-img-1302947942.cos.ap-guangzhou.myqcloud.com/" \ -F "key=user_img/test.jpg" \ -F "policy=<返回的policy>" \ -F "q-sign-algorithm=sha1" \ -F "q-ak=<返回的q-ak>" \ -F "q-key-time=<返回的q-key-time>" \ -F "q-signature=<返回的q-signature>" \ -F "file=@/path/to/test.jpg" ``` --- ## 📚 参考文档 - [腾讯云 COS POST Object 官方文档](https://cloud.tencent.com/document/product/436/14690) - [COS 请求签名算法](https://cloud.tencent.com/document/product/436/7778) --- ## ✅ 总结 修复后的签名已经完全符合 COS 规范: - ✅ 包含所有必需字段 - ✅ 签名算法正确 - ✅ Policy 格式正确 - ✅ 前端代码简单明了 **重新编译部署后即可正常使用!**