提交
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -57,8 +59,14 @@ func (c *FileController) Upload(ctx *gin.Context) {
|
||||
}
|
||||
storagePolicyID, _ := strconv.ParseUint(policyIDStr, 10, 64)
|
||||
|
||||
// 获取业务ID(可选)
|
||||
bizID := ctx.DefaultQuery("biz_id", "")
|
||||
if bizID == "" {
|
||||
bizID = ctx.PostForm("biz_id")
|
||||
}
|
||||
|
||||
// 调用服务层
|
||||
result, err := c.fileService.Upload(fileHeader, folderID, ownerID, storagePolicyID)
|
||||
result, err := c.fileService.Upload(fileHeader, folderID, ownerID, storagePolicyID, bizID)
|
||||
if err != nil {
|
||||
utils.ServerError(ctx, err.Error())
|
||||
return
|
||||
@@ -150,7 +158,7 @@ func (c *FileController) GetPreviewURL(ctx *gin.Context) {
|
||||
utils.Success(ctx, gin.H{"preview_url": previewURL})
|
||||
}
|
||||
|
||||
// Preview 文件预览(直接返回文件流, 浏览器内联展示)
|
||||
// Preview 文件预览(直接返回文件流, 浏览器内联展示, 支持Range请求)
|
||||
// GET /api/file/:id/preview
|
||||
func (c *FileController) Preview(ctx *gin.Context) {
|
||||
ownerID := middleware.GetCurrentUserID(ctx)
|
||||
@@ -168,9 +176,58 @@ func (c *FileController) Preview(ctx *gin.Context) {
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// 内联展示而非下载
|
||||
ctx.Header("Content-Disposition", "inline; filename=\""+file.Name+"\"")
|
||||
ctx.Header("Content-Type", file.MimeType)
|
||||
ctx.Header("Accept-Ranges", "bytes")
|
||||
|
||||
// Range请求: 视频/音频需要分段加载才能内联播放
|
||||
rangeHeader := ctx.GetHeader("Range")
|
||||
if rangeHeader != "" {
|
||||
fileSize := file.Size
|
||||
var start, end int64
|
||||
_, err := fmt.Sscanf(rangeHeader, "bytes=%d-%d", &start, &end)
|
||||
if err != nil {
|
||||
// 只有start没有end
|
||||
fmt.Sscanf(rangeHeader, "bytes=%d-", &start)
|
||||
end = fileSize - 1
|
||||
}
|
||||
if start >= fileSize || start < 0 {
|
||||
ctx.Status(http.StatusRequestedRangeNotSatisfiable)
|
||||
return
|
||||
}
|
||||
if end >= fileSize {
|
||||
end = fileSize - 1
|
||||
}
|
||||
length := end - start + 1
|
||||
|
||||
// 跳到起始位置
|
||||
if seeker, ok := reader.(io.Seeker); ok {
|
||||
seeker.Seek(start, io.SeekStart)
|
||||
}
|
||||
|
||||
ctx.Header("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
|
||||
ctx.Header("Content-Length", fmt.Sprintf("%d", length))
|
||||
ctx.Status(http.StatusPartialContent)
|
||||
|
||||
buf := make([]byte, 32*1024)
|
||||
remaining := length
|
||||
for remaining > 0 {
|
||||
toRead := int64(len(buf))
|
||||
if toRead > remaining {
|
||||
toRead = remaining
|
||||
}
|
||||
n, readErr := reader.Read(buf[:toRead])
|
||||
if n > 0 {
|
||||
ctx.Writer.Write(buf[:n])
|
||||
remaining -= int64(n)
|
||||
}
|
||||
if readErr != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.DataFromReader(http.StatusOK, file.Size, file.MimeType, reader, nil)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user