feat: 优化文件上传服务
- 添加文件大小和类型验证 - 支持更多文件格式 - 优化文件存储逻辑 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,23 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"x-agents/server/internal/repository"
|
||||
"x-agents/server/internal/service"
|
||||
)
|
||||
|
||||
type UploadHandler struct {
|
||||
uploadService *service.UploadService
|
||||
uploadService *service.UploadService
|
||||
knowledgeRepo *repository.KnowledgeRepository
|
||||
}
|
||||
|
||||
func NewUploadHandler(uploadService *service.UploadService) *UploadHandler {
|
||||
return &UploadHandler{uploadService: uploadService}
|
||||
func NewUploadHandler(uploadService *service.UploadService, knowledgeRepo *repository.KnowledgeRepository) *UploadHandler {
|
||||
return &UploadHandler{uploadService: uploadService, knowledgeRepo: knowledgeRepo}
|
||||
}
|
||||
|
||||
// Upload 上传文件
|
||||
@@ -58,3 +63,71 @@ func (h *UploadHandler) Delete(c *gin.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "File deleted"})
|
||||
}
|
||||
|
||||
// ProxyFile 代理文件访问(解决 MinIO 内网地址和 HTTPS 问题)
|
||||
func (h *UploadHandler) ProxyFile(c *gin.Context) {
|
||||
fileKey := c.Query("key")
|
||||
kbID := c.Query("kb_id")
|
||||
|
||||
if fileKey == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "File key is required"})
|
||||
return
|
||||
}
|
||||
|
||||
var content io.Reader
|
||||
var contentType string
|
||||
|
||||
// 如果提供了知识库 ID,使用知识库的存储配置
|
||||
if kbID != "" && h.knowledgeRepo != nil {
|
||||
kb, err := h.knowledgeRepo.FindByID(kbID)
|
||||
if err == nil && kb.StorageConfig.Type == "minio" {
|
||||
reader, ct, err := h.uploadService.GetFileContentWithConfig(fileKey, kb.StorageConfig)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
content = reader
|
||||
contentType = ct
|
||||
defer reader.Close()
|
||||
} else {
|
||||
// 使用全局配置
|
||||
reader, ct, err := h.uploadService.GetFileContent(fileKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
content = reader
|
||||
contentType = ct
|
||||
defer reader.Close()
|
||||
}
|
||||
} else {
|
||||
// 使用全局配置
|
||||
reader, ct, err := h.uploadService.GetFileContent(fileKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
content = reader
|
||||
contentType = ct
|
||||
defer reader.Close()
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
// 如果 Content-Type 是 application/octet-stream,根据文件扩展名推断
|
||||
if contentType == "application/octet-stream" {
|
||||
ext := filepath.Ext(fileKey)
|
||||
if detected := mime.TypeByExtension(ext); detected != "" {
|
||||
contentType = detected
|
||||
}
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
c.Header("Content-Type", contentType)
|
||||
} else {
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
}
|
||||
c.Header("Content-Disposition", "inline")
|
||||
|
||||
// 直接流式输出文件内容
|
||||
c.DataFromReader(http.StatusOK, -1, contentType, content, nil)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user