Explorar el Código

✨ feat(files): 添加分片上传策略API

- 新增multipart-policy路由,支持大文件分片上传
- 实现分片上传策略生成逻辑,返回上传ID和分片URL列表
- 定义分片上传请求参数验证Schema,包括fileKey、totalSize和partSize
- 添加认证中间件确保安全访问
- 完善错误处理机制,返回适当的错误状态码和消息
yourname hace 8 meses
padre
commit
5edbd1be26
Se han modificado 2 ficheros con 98 adiciones y 0 borrados
  1. 2 0
      src/server/api/files/index.ts
  2. 96 0
      src/server/api/files/multipart-policy/post.ts

+ 2 - 0
src/server/api/files/index.ts

@@ -1,5 +1,6 @@
 import { OpenAPIHono } from '@hono/zod-openapi';
 import uploadPolicyRoute from './upload-policy/post';
+import multipartPolicyRoute from './multipart-policy/post';
 import getUrlRoute from './[id]/get-url';
 import deleteRoute from './[id]/delete';
 import { AuthContext } from '@/server/types/context';
@@ -23,6 +24,7 @@ const fileRoutes = createCrudRoutes({
 // 创建路由实例并聚合所有子路由
 const app = new OpenAPIHono<AuthContext>()
   .route('/upload-policy', uploadPolicyRoute)
+  .route('/multipart-policy', multipartPolicyRoute)
   .route('/{id}', getUrlRoute)
   .route('/', fileRoutes)
   .route('/{id}', deleteRoute)

+ 96 - 0
src/server/api/files/multipart-policy/post.ts

@@ -0,0 +1,96 @@
+import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
+import { FileService } from '@/server/modules/files/file.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { AppDataSource } from '@/server/data-source';
+import { AuthContext } from '@/server/types/context';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+// 创建分片上传策略请求Schema
+const CreateMultipartUploadPolicyDto = z.object({
+  fileKey: z.string().openapi({
+    description: '文件键名',
+    example: 'documents/report.pdf'
+  }),
+  totalSize: z.coerce.number().int().positive().openapi({
+    description: '文件总大小(字节)',
+    example: 10485760
+  }),
+  partSize: z.coerce.number().int().positive().openapi({
+    description: '分片大小(字节)',
+    example: 5242880
+  })
+});
+
+// 创建分片上传策略路由定义
+const createMultipartUploadPolicyRoute = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: CreateMultipartUploadPolicyDto }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '生成分片上传策略成功',
+      content: {
+        'application/json': {
+          schema: z.object({
+            uploadId: z.string().openapi({
+              description: '分片上传ID',
+              example: '123e4567-e89b-12d3-a456-426614174000'
+            }),
+            bucket: z.string().openapi({
+              description: '存储桶名称',
+              example: 'my-bucket'
+            }),
+            key: z.string().openapi({
+              description: '文件键名',
+              example: 'documents/report.pdf'
+            }),
+            host: z.string().openapi({
+              description: 'MinIO主机地址',
+              example: 'minio.example.com'
+            }),
+            partUrls: z.array(z.string()).openapi({
+              description: '分片上传URL列表',
+              example: [
+                'https://minio.example.com/my-bucket/documents/report.pdf?uploadId=123e4567-e89b-12d3-a456-426614174000&partNumber=1',
+                'https://minio.example.com/my-bucket/documents/report.pdf?uploadId=123e4567-e89b-12d3-a456-426614174000&partNumber=2'
+              ]
+            })
+          })
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// 创建文件服务实例
+const fileService = new FileService(AppDataSource);
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(createMultipartUploadPolicyRoute, async (c) => {
+  try {
+    const data = await c.req.json();
+    const result = await fileService.createMultipartUploadPolicy(data);
+    
+    return c.json(result, 200);
+  } catch (error) {
+    const message = error instanceof Error ? error.message : '生成分片上传策略失败';
+    return c.json({ code: 500, message }, 500);
+  }
+});
+
+export default app;