# COS POST 表单上传指南

## 问题说明

如果出现 403 错误，通常是因为前端提交的表单字段名不符合 COS 要求。

---

## ✅ 正确的前端上传代码

### 方式1：使用 COS 标准字段（推荐）

```javascript
// 1. 获取签名
const response = await fetch('/user/oss/post-signature', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    userId: '123',
    fileName: 'avatar.jpg'
  })
});

const signData = await response.json();
const data = signData.data;

// 2. 构造表单数据（COS 标准字段）
const formData = new FormData();
formData.append('key', data.dir + 'your-file-name.jpg');  // 文件路径
formData.append('policy', data.policy);                    // Policy
formData.append('q-sign-algorithm', 'sha1');               // 签名算法
formData.append('q-ak', data['q-ak']);                     // SecretId
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 fileUrl = data.host + '/' + data.dir + 'your-file-name.jpg';
  console.log('上传成功:', fileUrl);
}
```

---

### 方式2：兼容 OSS 的字段名

```javascript
// 如果前端代码还在用 OSS 的字段名，可以这样：
const formData = new FormData();
formData.append('key', data.dir + 'your-file-name.jpg');
formData.append('policy', data.policy);
formData.append('OSSAccessKeyId', data.accessKeyId);  // 兼容 OSS
formData.append('signature', data.signature);         // 兼容 OSS
formData.append('file', file);

// 但这种方式可能不被 COS 接受，建议使用方式1
```

---

## 📋 后端返回的字段说明

| 字段名 | 用途 | 说明 |
|--------|------|------|
| `policy` | Policy Base64 | 必须 |
| `q-sign-algorithm` | 签名算法 | 固定为 "sha1" |
| `q-ak` | SecretId | COS 密钥 ID |
| `q-signature` | 签名 | HMAC-SHA1 签名 |
| `host` | 上传地址 | COS 存储桶域名 |
| `dir` | 文件目录 | 文件存储路径前缀 |

---

## ⚠️ 常见错误

### 1. 403 Forbidden - 签名错误
**原因：** 表单字段名不对或缺少必要字段

**解决：** 确保使用 COS 标准字段名：
- ✅ `q-ak`（不是 `accessKeyId` 或 `OSSAccessKeyId`）
- ✅ `q-signature`（不是 `signature`）
- ✅ `q-sign-algorithm`

### 2. 403 Forbidden - Key 不匹配
**原因：** `key` 字段的值不符合 Policy 中的前缀限制

**解决：** 确保 `key` 以 `data.dir` 开头：
```javascript
formData.append('key', data.dir + fileName);  // ✅ 正确
formData.append('key', fileName);             // ❌ 错误
```

### 3. CORS 错误
**原因：** COS 存储桶未配置跨域规则

**解决：** 在腾讯云 COS 控制台配置 CORS（见主文档）

---

## 🧪 测试上传

使用以下 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-signature=<返回的q-signature>" \
  -F "file=@/path/to/test.jpg"
```

---

## 📚 参考文档

- [腾讯云 COS POST 表单上传](https://cloud.tencent.com/document/product/436/14690)
- [COS 签名算法](https://cloud.tencent.com/document/product/436/7778)
