563 lines
14 KiB
Markdown
563 lines
14 KiB
Markdown
# 管理端OSS文件上传接口文档
|
||
|
||
## 📋 概述
|
||
|
||
管理端OSS文件上传接口提供了完整的文件管理功能,包括文件上传签名生成、文件删除、批量删除和文件信息查询。**管理端和用户端的文件存储在同一目录下**(`user_img/`),便于统一管理。
|
||
|
||
### 基础信息
|
||
- **基础路径**: `/admin/oss`
|
||
- **权限要求**: 需要管理员或工作人员JWT Token
|
||
- **文件存储**: 与用户端共享同一目录 (`user_img/`)
|
||
- **最大文件**: 500MB
|
||
- **有效期**: 2小时
|
||
|
||
---
|
||
|
||
## 🔐 认证方式
|
||
|
||
所有管理端接口都需要在请求头中携带JWT Token:
|
||
|
||
```http
|
||
Authorization: Bearer {your_admin_jwt_token}
|
||
```
|
||
|
||
---
|
||
|
||
## 📡 API接口列表
|
||
|
||
### 1. 生成OSS POST签名
|
||
|
||
**接口地址**: `POST /admin/oss/post-signature`
|
||
|
||
**功能描述**: 生成管理端文件上传的OSS POST签名,支持多种文件格式和大文件上传。
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"fileName": "banner.jpg",
|
||
"directory": "banners",
|
||
"description": "Banner图片",
|
||
"fileCategory": "image",
|
||
"maxSizeMB": 50
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| fileName | string | ✅ | 文件名,包含扩展名 |
|
||
| directory | string | ❌ | 子目录名称(不包含user_img前缀) |
|
||
| description | string | ❌ | 文件描述 |
|
||
| fileCategory | string | ❌ | 文件分类:image/document/compressed/video/audio/other |
|
||
| maxSizeMB | integer | ❌ | 最大文件大小(MB),默认50MB,最大500MB |
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "管理端POST签名生成成功",
|
||
"data": {
|
||
"version": "OSS4-HMAC-SHA256",
|
||
"policy": "eyJleHBpcmF0aW9uIjoiMjAyNC0xMi0yNVQxNDowMDowMC4wMDBaIi...",
|
||
"x_oss_credential": "LTAI5t7Cn8mLa9K8NQy7S9Vj/20241225/cn-hangzhou/oss/aliyun_v4_request",
|
||
"x_oss_date": "20241225T120000Z",
|
||
"signature": "a1b2c3d4e5f6789...",
|
||
"security_token": "",
|
||
"dir": "user_img/banners/",
|
||
"host": "https://oss-1818ai-user-img.oss-cn-hangzhou.aliyuncs.com",
|
||
"accessKeyId": "LTAI5t7Cn8mLa9K8NQy7S9Vj",
|
||
"adminId": "123",
|
||
"fileName": "banner.jpg",
|
||
"fileType": "image",
|
||
"maxFileSize": 52428800,
|
||
"maxFileSizeMB": 50,
|
||
"supportedFormats": [
|
||
"图片: jpg, jpeg, png, gif, bmp, webp, svg, ico, tiff",
|
||
"文档: pdf, txt, md, json, xml, csv, doc, docx, xls, xlsx, ppt, pptx",
|
||
"压缩包: zip, rar, 7z, tar, gz, bz2, xz",
|
||
"音频: mp3, wav, flac, aac, ogg, wma",
|
||
"视频: mp4, avi, mov, wmv, flv, mkv, webm",
|
||
"其他: html, css, js, sql, log"
|
||
],
|
||
"uploadTips": "支持常见图片格式,建议使用JPG/PNG格式以获得更好的兼容性。"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 删除文件
|
||
|
||
**接口地址**: `DELETE /admin/oss/file`
|
||
|
||
**功能描述**: 删除指定的OSS文件。
|
||
|
||
#### 请求参数
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| objectKey | string | ✅ | 文件的完整路径,如:user_img/banners/banner.jpg |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
DELETE /admin/oss/file?objectKey=user_img/banners/banner.jpg
|
||
Authorization: Bearer {admin_jwt_token}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "操作成功",
|
||
"data": "文件删除成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 批量删除文件
|
||
|
||
**接口地址**: `POST /admin/oss/batch-delete`
|
||
|
||
**功能描述**: 批量删除多个OSS文件。
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
[
|
||
"user_img/banners/banner1.jpg",
|
||
"user_img/banners/banner2.jpg",
|
||
"user_img/documents/file.pdf"
|
||
]
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "批量删除操作完成",
|
||
"data": {
|
||
"success": [
|
||
"user_img/banners/banner1.jpg",
|
||
"user_img/banners/banner2.jpg"
|
||
],
|
||
"failed": [
|
||
"user_img/documents/file.pdf"
|
||
],
|
||
"total": 3,
|
||
"successCount": 2,
|
||
"failedCount": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 获取文件信息
|
||
|
||
**接口地址**: `GET /admin/oss/file-info`
|
||
|
||
**功能描述**: 获取OSS文件的详细信息。
|
||
|
||
#### 请求参数
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| objectKey | string | ✅ | 文件的完整路径 |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
GET /admin/oss/file-info?objectKey=user_img/banners/banner.jpg
|
||
Authorization: Bearer {admin_jwt_token}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "获取文件信息成功",
|
||
"data": {
|
||
"objectKey": "user_img/banners/banner.jpg",
|
||
"size": 1024000,
|
||
"lastModified": "2024-12-25T12:00:00.000Z",
|
||
"contentType": "image/jpeg"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 获取上传配置
|
||
|
||
**接口地址**: `GET /admin/oss/upload-config`
|
||
|
||
**功能描述**: 获取管理端文件上传的配置信息。
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "获取上传配置成功",
|
||
"data": {
|
||
"maxFileSize": 524288000,
|
||
"maxFileSizeMB": 500,
|
||
"supportedFormats": [
|
||
"图片: jpg, jpeg, png, gif, bmp, webp, svg, ico, tiff",
|
||
"文档: pdf, txt, md, json, xml, csv, doc, docx, xls, xlsx, ppt, pptx",
|
||
"压缩包: zip, rar, 7z, tar, gz, bz2, xz",
|
||
"音频: mp3, wav, flac, aac, ogg, wma",
|
||
"视频: mp4, avi, mov, wmv, flv, mkv, webm",
|
||
"其他: html, css, js, sql, log"
|
||
],
|
||
"uploadDirectories": [
|
||
"banners",
|
||
"images",
|
||
"documents",
|
||
"videos",
|
||
"audios",
|
||
"uploads"
|
||
],
|
||
"tips": "管理端支持多种文件格式,最大支持500MB文件上传。文件将与用户端文件存储在同一目录下,建议根据用途选择合适的子目录。"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 前端使用示例
|
||
|
||
### JavaScript/Vue.js 示例
|
||
|
||
```javascript
|
||
class AdminOssUploader {
|
||
constructor(baseURL, token) {
|
||
this.baseURL = baseURL;
|
||
this.token = token;
|
||
}
|
||
|
||
// 获取上传签名
|
||
async getUploadSignature(fileName, directory = 'uploads', maxSizeMB = 50) {
|
||
const response = await fetch(`${this.baseURL}/admin/oss/post-signature`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${this.token}`
|
||
},
|
||
body: JSON.stringify({
|
||
fileName,
|
||
directory,
|
||
fileCategory: this.getFileCategory(fileName),
|
||
maxSizeMB
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
if (result.code === 200) {
|
||
return result.data;
|
||
}
|
||
throw new Error(result.message);
|
||
}
|
||
|
||
// 上传文件到OSS
|
||
async uploadFile(file, directory = 'uploads') {
|
||
try {
|
||
// 1. 获取签名
|
||
const signature = await this.getUploadSignature(file.name, directory);
|
||
|
||
// 2. 构建FormData
|
||
const formData = new FormData();
|
||
formData.append('key', `${signature.dir}${this.generateFileName(file.name)}`);
|
||
formData.append('policy', signature.policy);
|
||
formData.append('x-oss-credential', signature.x_oss_credential);
|
||
formData.append('x-oss-date', signature.x_oss_date);
|
||
formData.append('x-oss-signature-version', signature.x_oss_signature_version);
|
||
formData.append('x-oss-signature', signature.x_oss_signature);
|
||
formData.append('success_action_status', '200');
|
||
formData.append('file', file);
|
||
|
||
// 3. 上传到OSS
|
||
const uploadResponse = await fetch(signature.host, {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
if (uploadResponse.ok) {
|
||
const uploadedUrl = `${signature.host}/${formData.get('key')}`;
|
||
return {
|
||
success: true,
|
||
url: uploadedUrl,
|
||
key: formData.get('key')
|
||
};
|
||
}
|
||
throw new Error('Upload failed');
|
||
} catch (error) {
|
||
console.error('Upload error:', error);
|
||
return { success: false, error: error.message };
|
||
}
|
||
}
|
||
|
||
// 删除文件
|
||
async deleteFile(objectKey) {
|
||
const response = await fetch(`${this.baseURL}/admin/oss/file?objectKey=${encodeURIComponent(objectKey)}`, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Authorization': `Bearer ${this.token}`
|
||
}
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result.code === 200;
|
||
}
|
||
|
||
// 批量删除文件
|
||
async batchDeleteFiles(objectKeys) {
|
||
const response = await fetch(`${this.baseURL}/admin/oss/batch-delete`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${this.token}`
|
||
},
|
||
body: JSON.stringify(objectKeys)
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result.data;
|
||
}
|
||
|
||
// 生成唯一文件名
|
||
generateFileName(originalName) {
|
||
const timestamp = Date.now();
|
||
const random = Math.random().toString(36).substring(2);
|
||
const ext = originalName.substring(originalName.lastIndexOf('.'));
|
||
return `${timestamp}_${random}${ext}`;
|
||
}
|
||
|
||
// 获取文件分类
|
||
getFileCategory(fileName) {
|
||
const ext = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
|
||
|
||
if (['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'].includes(ext)) {
|
||
return 'image';
|
||
} else if (['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv'].includes(ext)) {
|
||
return 'video';
|
||
} else if (['.mp3', '.wav', '.flac', '.aac', '.ogg'].includes(ext)) {
|
||
return 'audio';
|
||
} else if (['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx'].includes(ext)) {
|
||
return 'document';
|
||
} else if (['.zip', '.rar', '.7z', '.tar', '.gz'].includes(ext)) {
|
||
return 'compressed';
|
||
}
|
||
return 'other';
|
||
}
|
||
}
|
||
|
||
// 使用示例
|
||
const uploader = new AdminOssUploader('https://your-api.com', 'your-admin-token');
|
||
|
||
// 上传Banner图片
|
||
document.getElementById('bannerInput').addEventListener('change', async (e) => {
|
||
const file = e.target.files[0];
|
||
if (file) {
|
||
const result = await uploader.uploadFile(file, 'banners');
|
||
if (result.success) {
|
||
console.log('上传成功:', result.url);
|
||
} else {
|
||
console.error('上传失败:', result.error);
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
### React Hook 示例
|
||
|
||
```jsx
|
||
import { useState, useCallback } from 'react';
|
||
|
||
const useAdminOssUpload = (token) => {
|
||
const [uploading, setUploading] = useState(false);
|
||
const [progress, setProgress] = useState(0);
|
||
|
||
const uploadFile = useCallback(async (file, directory = 'uploads') => {
|
||
setUploading(true);
|
||
setProgress(0);
|
||
|
||
try {
|
||
// 获取签名
|
||
const response = await fetch('/admin/oss/post-signature', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: JSON.stringify({
|
||
fileName: file.name,
|
||
directory,
|
||
maxSizeMB: Math.ceil(file.size / (1024 * 1024))
|
||
})
|
||
});
|
||
|
||
const { data: signature } = await response.json();
|
||
|
||
// 上传到OSS
|
||
const formData = new FormData();
|
||
const fileKey = `${signature.dir}${Date.now()}_${file.name}`;
|
||
|
||
formData.append('key', fileKey);
|
||
formData.append('policy', signature.policy);
|
||
formData.append('x-oss-credential', signature.x_oss_credential);
|
||
formData.append('x-oss-date', signature.x_oss_date);
|
||
formData.append('x-oss-signature-version', signature.x_oss_signature_version);
|
||
formData.append('x-oss-signature', signature.x_oss_signature);
|
||
formData.append('success_action_status', '200');
|
||
formData.append('file', file);
|
||
|
||
const uploadResponse = await fetch(signature.host, {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
if (uploadResponse.ok) {
|
||
setProgress(100);
|
||
return {
|
||
success: true,
|
||
url: `${signature.host}/${fileKey}`,
|
||
key: fileKey
|
||
};
|
||
}
|
||
throw new Error('Upload failed');
|
||
|
||
} catch (error) {
|
||
return { success: false, error: error.message };
|
||
} finally {
|
||
setUploading(false);
|
||
}
|
||
}, [token]);
|
||
|
||
return { uploadFile, uploading, progress };
|
||
};
|
||
|
||
// 使用示例
|
||
const AdminFileUpload = () => {
|
||
const token = localStorage.getItem('adminToken');
|
||
const { uploadFile, uploading } = useAdminOssUpload(token);
|
||
|
||
const handleUpload = async (e) => {
|
||
const file = e.target.files[0];
|
||
if (file) {
|
||
const result = await uploadFile(file, 'banners');
|
||
if (result.success) {
|
||
alert('上传成功: ' + result.url);
|
||
} else {
|
||
alert('上传失败: ' + result.error);
|
||
}
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div>
|
||
<input type="file" onChange={handleUpload} disabled={uploading} />
|
||
{uploading && <p>上传中...</p>}
|
||
</div>
|
||
);
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 目录结构说明
|
||
|
||
### 存储路径规则
|
||
|
||
- **基础目录**: `user_img/` (与用户端共享)
|
||
- **完整路径**: `user_img/{directory}/{filename}`
|
||
|
||
### 推荐目录结构
|
||
|
||
```
|
||
user_img/
|
||
├── banners/ # Banner图片
|
||
├── images/ # 通用图片
|
||
├── documents/ # 文档文件
|
||
├── videos/ # 视频文件
|
||
├── audios/ # 音频文件
|
||
├── uploads/ # 默认上传目录
|
||
└── {custom}/ # 自定义目录
|
||
```
|
||
|
||
### 文件命名建议
|
||
|
||
```javascript
|
||
// 推荐的文件命名格式
|
||
const generateFileName = (originalName) => {
|
||
const timestamp = Date.now();
|
||
const random = Math.random().toString(36).substring(2);
|
||
const ext = originalName.substring(originalName.lastIndexOf('.'));
|
||
return `${timestamp}_${random}${ext}`;
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ 注意事项
|
||
|
||
### 文件大小限制
|
||
- **用户端**: 最大10MB
|
||
- **管理端**: 最大500MB (可通过maxSizeMB参数调整)
|
||
|
||
### 文件格式支持
|
||
- **图片**: jpg, jpeg, png, gif, bmp, webp, svg, ico, tiff
|
||
- **文档**: pdf, txt, md, json, xml, csv, doc, docx, xls, xlsx, ppt, pptx
|
||
- **压缩包**: zip, rar, 7z, tar, gz, bz2, xz
|
||
- **音频**: mp3, wav, flac, aac, ogg, wma
|
||
- **视频**: mp4, avi, mov, wmv, flv, mkv, webm
|
||
- **其他**: html, css, js, sql, log
|
||
|
||
### 安全性
|
||
- 所有管理端接口都需要JWT认证
|
||
- 文件类型严格验证
|
||
- 文件大小限制保护
|
||
- 操作日志完整记录
|
||
|
||
### 错误码
|
||
- **200**: 操作成功
|
||
- **400**: 请求参数错误
|
||
- **401**: 未授权访问
|
||
- **403**: 权限不足
|
||
- **404**: 文件不存在
|
||
- **500**: 服务器内部错误
|
||
|
||
---
|
||
|
||
## 🔄 与用户端的差异
|
||
|
||
| 特性 | 用户端 | 管理端 |
|
||
|------|--------|--------|
|
||
| **权限** | 无需认证 | 需要管理员Token |
|
||
| **文件大小** | 10MB | 500MB |
|
||
| **文件格式** | 基础格式 | 全格式支持 |
|
||
| **目录** | user_img/ | user_img/ (相同) |
|
||
| **有效期** | 1小时 | 2小时 |
|
||
| **管理功能** | 仅上传 | 完整CRUD |
|
||
|
||
---
|
||
|
||
## 📞 技术支持
|
||
|
||
如遇到问题,请检查:
|
||
1. JWT Token是否有效
|
||
2. 文件格式是否支持
|
||
3. 文件大小是否超限
|
||
4. 网络连接是否正常
|
||
5. OSS配置是否正确
|
||
|
||
---
|
||
|
||
*最后更新时间: 2024-12-25*
|