API参考文档 (API Reference)
本文档提供文件模块所有API接口的完整说明,包括请求参数、响应格式、错误码和使用示例。
🌐 基本信息
Base URL
http://localhost:8080/api/v1/files
认证方式
所有API需要JWT认证,请在请求头中携带token:
Authorization: Bearer <your_jwt_token>
响应格式
所有API返回统一的JSON格式:
{
"code": 0, // 0=成功, 非0=错误码
"message": "成功", // 提示消息
"data": { ... }, // 响应数据
"timestamp": 1702465200000
}
📋 API列表
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /presigned | 生成预签名上传URL |
| PATCH | /{fileId}/confirm | 确认上传完成 |
| GET | /{fileId} | 查询文件信息 |
| GET | /{fileId}/access-url | 获取文件访问URL |
| DELETE | /{fileId} | 删除文件 |
1. 生成预签名上传URL
请求
POST /api/v1/files/presigned
Content-Type: application/json
Authorization: Bearer <token>
{
"fileName": "example.jpg",
"fileSize": 1024000,
"fileType": "image/jpeg",
"md5": "abc123def456"
}
请求参数
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| fileName | String | ✅ | 文件名(含扩展名) | "avatar.jpg" |
| fileSize | Long | ✅ | 文件大小(字节) | 1024000 |
| fileType | String | ✅ | MIME类型 | "image/jpeg" |
| md5 | String | ❌ | MD5哈希(秒传用) | "a1b2c3..." |
响应
成功(普通上传):
{
"code": 0,
"message": "成功",
"data": {
"uploadUrl": "https://s3.bitiful.net/blog-files/uploads/2025/12/13/xxx.jpg?X-Amz-...",
"fileId": "1999842821338591234",
"fileKey": "uploads/2025/12/13/abc123.jpg",
"instant": false
}
}
成功(秒传):
{
"code": 0,
"message": "成功",
"data": {
"uploadUrl": null,
"fileId": "1888765432109876543",
"fileKey": "uploads/2025/12/10/old123.jpg",
"instant": true
}
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| uploadUrl | String | 预签名URL(秒传时为null) |
| fileId | String | 文件ID(Long序列化为String) |
| fileKey | String | 云端存储路径 |
| instant | Boolean | 是否秒传 |
使用示例
const response = await fetch('/api/v1/files/presigned', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
fileName: file.name,
fileSize: file.size,
fileType: file.type,
md5: await calculateMD5(file)
})
});
const {uploadUrl, fileId, instant} = (await response.json()).data;
if (instant) {
console.log('⚡ 秒传成功');
} else {
await fetch(uploadUrl, {method: 'PUT', body: file});
}
2. 确认上传完成
请求
PATCH /api/v1/files/1999842821338591234/confirm
Authorization: Bearer <token>
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
| fileId | Long | 文件ID |
响应
{
"code": 0,
"message": "成功",
"data": null
}
注意事项
- ✅ 幂等性:重复调用不会报错
- ✅ 仅更新状态:PENDING → COMPLETED
- ⚠️ 不验证文件是否真实存在于云端
3. 查询文件信息
请求
GET /api/v1/files/1999842821338591234
Authorization: Bearer <token>
响应
{
"code": 0,
"message": "成功",
"data": {
"id": "1999842821338591234",
"fileName": "example.jpg",
"fileSize": 1024000,
"fileType": "image/jpeg",
"fileKey": "uploads/2025/12/13/abc123.jpg",
"md5": "a1b2c3def456",
"storageType": "BITIFUL",
"bucketName": "blog-files",
"uploadStatus": 1,
"createTime": "2025-12-13T14:30:00",
"updateTime": "2025-12-13T14:35:00"
}
}
4. 获取文件访问URL
请求
GET /api/v1/files/1999842821338591234/access-url?expireMinutes=60
Authorization: Bearer <token>
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| expireMinutes | Integer | ❌ | 60 | 过期时间(分钟,最大60) |
响应
{
"code": 0,
"message": "成功",
"data": "https://s3.bitiful.net/blog-files/uploads/2025/12/13/abc123.jpg?X-Amz-Expires=3600&..."
}
使用示例
const response = await fetch(`/api/v1/files/${fileId}/access-url`, {
headers: {'Authorization': `Bearer ${token}`}
});
const accessUrl = (await response.json()).data;
// 显示图片
document.getElementById('img').src = accessUrl;
// 或下载文件
window.open(accessUrl);
5. 删除文件
请求
DELETE /api/v1/files/1999842821338591234
Authorization: Bearer <token>
响应
{
"code": 0,
"message": "成功",
"data": null
}
删除逻辑
- 逻辑删除:数据库记录标记为删除(is_deleted=1)
- 物理删除:异步调用云存储API删除文件
- 幂等性:文件不存在时也返回成功
⚠️ 错误码
通用错误码
| 错误码 | 说明 | HTTP状态 |
|---|---|---|
| 0 | 成功 | 200 |
| 10001 | 参数验证失败 | 400 |
| 10002 | 未授权 | 401 |
| 10003 | 无权限 | 403 |
文件模块错误码
| 错误码 | 常量名 | 说明 | HTTP状态 |
|---|---|---|---|
| 11001 | FILE_UPLOAD_FAILED | 文件上传失败 | 500 |
| 11002 | FILE_INVALID_TYPE | 文件类型不允许 | 400 |
| 11003 | FILE_EXCEED_MAX_SIZE | 文件超过大小限制 | 400 |
| 11004 | FILE_INVALID_NAME | 文件名无效 | 400 |
| 11006 | FILE_STORAGE_ERROR | 存储服务异常 | 500 |
| 11007 | FILE_PRESIGNED_URL_FAILED | 预签名URL生成失败 | 500 |
| 11008 | FILE_NOT_FOUND | 文件不存在 | 404 |
错误响应示例
{
"code": 11003,
"message": "文件大小超过限制(最大10MB)",
"data": null,
"timestamp": 1702465200000
}
📝 完整上传流程示例
async function uploadFile(file) {
const token = localStorage.getItem('token');
try {
// 1. 计算MD5
const md5 = await calculateMD5(file);
// 2. 请求预签名URL
const presignedResp = await fetch('/api/v1/files/presigned', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
fileName: file.name,
fileSize: file.size,
fileType: file.type,
md5: md5
})
});
if (!presignedResp.ok) {
throw new Error('获取上传URL失败');
}
const {uploadUrl, fileId, instant} = (await presignedResp.json()).data;
// 3. 判断是否秒传
if (instant) {
console.log('⚡ 秒传成功,fileId:', fileId);
return fileId;
}
// 4. 上传到云端
const uploadResp = await fetch(uploadUrl, {
method: 'PUT',
body: file
});
if (!uploadResp.ok) {
throw new Error('上传失败');
}
// 5. 确认上传
const confirmResp = await fetch(`/api/v1/files/${fileId}/confirm`, {
method: 'PATCH',
headers: {'Authorization': `Bearer ${token}`}
});
if (!confirmResp.ok) {
throw new Error('确认上传失败');
}
console.log('🎉 上传成功,fileId:', fileId);
return fileId;
} catch (error) {
console.error('上传失败:', error);
throw error;
}
}
// 使用示例
const fileId = await uploadFile(document.getElementById('file').files[0]);
// 获取访问URL
const accessResp = await fetch(`/api/v1/files/${fileId}/access-url`, {
headers: {'Authorization': `Bearer ${token}`}
});
const accessUrl = (await accessResp.json()).data;
// 显示图片
document.getElementById('preview').src = accessUrl;
🧪 Postman测试集合
环境变量
{
"base_url": "http://localhost:8080",
"token": "your_jwt_token"
}
请求集合
创建Postman Collection,包含以下请求:
-
Generate Presigned URL
- Method: POST
- URL:
{{base_url}}/api/v1/files/presigned - Headers:
Authorization: Bearer {{token}} - Body: (见上文)
-
Confirm Upload
- Method: PATCH
- URL:
{{base_url}}/api/v1/files/{{fileId}}/confirm
-
Get File Info
- Method: GET
- URL:
{{base_url}}/api/v1/files/{{fileId}}
-
Get Access URL
- Method: GET
- URL:
{{base_url}}/api/v1/files/{{fileId}}/access-url
-
Delete File
- Method: DELETE
- URL:
{{base_url}}/api/v1/files/{{fileId}}
📚 相关文档
🎓 提示:本文档已包含完整的错误码说明,请参见上方"错误码"章节。