Skip to content

Commit

Permalink
refactor: 修改文件上传接口
Browse files Browse the repository at this point in the history
  • Loading branch information
SugarMGP committed Dec 12, 2024
1 parent df8e69b commit 71af29a
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 107 deletions.
2 changes: 0 additions & 2 deletions app/apiException/apiException.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ var (
FileSizeExceedError = NewError(200515, log.LevelInfo, "文件大小超限")
FileNotImageError = NewError(200516, log.LevelInfo, "上传的文件不是图片")

NotInit = NewError(200404, log.LevelWarn, http.StatusText(http.StatusNotFound))
NotFound = NewError(200404, log.LevelWarn, http.StatusText(http.StatusNotFound))
Unknown = NewError(300500, log.LevelError, "系统异常,请稍后重试!")
)

// Error 方法实现了 error 接口,返回错误的消息内容
Expand Down
39 changes: 10 additions & 29 deletions app/controllers/objectController/upload.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
//nolint:all
package objectController

import (
"errors"
"image"
"io"
"mime/multipart"

"4u-go/app/apiException"
Expand All @@ -15,8 +13,7 @@ import (
)

type uploadFileData struct {
UploadType string `form:"type" binding:"required"`
File *multipart.FileHeader `form:"file" binding:"required"`
File *multipart.FileHeader `form:"file" binding:"required"`
}

// UploadFile 上传文件
Expand All @@ -27,7 +24,6 @@ func UploadFile(c *gin.Context) {
return
}

uploadType := data.UploadType
fileSize := data.File.Size
file, err := data.File.Open()
if err != nil {
Expand All @@ -42,40 +38,25 @@ func UploadFile(c *gin.Context) {
}(file)

// 获取文件信息
contentType, fileExt, err := objectService.GetFileInfo(file, fileSize, uploadType)
if errors.Is(err, objectService.ErrSizeExceeded) {
apiException.AbortWithException(c, apiException.FileSizeExceedError, err)
if fileSize > objectService.ImageLimit {
apiException.AbortWithException(c, apiException.FileSizeExceedError, nil)
return
}
if errors.Is(err, objectService.ErrUnsupportedUploadType) {
apiException.AbortWithException(c, apiException.ParamError, err)

reader, size, err := objectService.ConvertToWebP(file)
if errors.Is(err, image.ErrFormat) {
apiException.AbortWithException(c, apiException.FileNotImageError, err)
return
}
if err != nil {
apiException.AbortWithException(c, apiException.ServerError, err)
return
}

var fileReader io.Reader = file
if uploadType == objectService.TypeImage {
reader, size, err := objectService.ConvertToWebP(file)
if err != nil {
if errors.Is(err, image.ErrFormat) {
apiException.AbortWithException(c, apiException.FileNotImageError, err)
return
}
zap.L().Error("转换图片到 WebP 失败", zap.Error(err))
} else { // 若转换成功则替代原文件
fileReader = reader
fileSize = size
fileExt = ".webp"
contentType = "image/webp"
}
}
contentType := "image/webp"

// 上传文件
objectKey := objectService.GenerateObjectKey(uploadType, fileExt)
objectUrl, err := objectService.PutObject(objectKey, fileReader, fileSize, contentType)
objectKey := objectService.GenerateObjectKey("image", ".webp")
objectUrl, err := objectService.PutObject(objectKey, reader, size, contentType)
if err != nil {
apiException.AbortWithException(c, apiException.ServerError, err)
return
Expand Down
77 changes: 4 additions & 73 deletions app/services/objectService/objectService.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,102 +2,33 @@ package objectService

import (
"bytes"
"errors"
"fmt"
"image"
_ "image/gif" // 注册解码器
_ "image/jpeg"
_ "image/png"
"io"
"mime/multipart"
"time"

"github.com/chai2010/webp"
"github.com/dustin/go-humanize"
"github.com/gabriel-vasile/mimetype"
uuid "github.com/satori/go.uuid"
_ "golang.org/x/image/bmp" // 注册解码器
_ "golang.org/x/image/tiff"
_ "golang.org/x/image/webp"
)

var (
// ErrUnsupportedUploadType 不支持的上传类型
ErrUnsupportedUploadType = errors.New("unsupported upload type")

// ErrSizeExceeded 文件大小超限
ErrSizeExceeded = errors.New("file size exceeded")
)

const (
// TypeImage 图片
TypeImage = "image"

// TypeAttachment 附件
TypeAttachment = "attachment"
)

var uploadTypeLimits = map[string]int64{
TypeImage: humanize.MByte * 10,
TypeAttachment: humanize.MByte * 100,
}

// GetFileInfo 获取文件基本信息
func GetFileInfo(
file multipart.File,
fileSize int64,
uploadType string,
) (
contentType string,
fileExt string,
err error,
) {
// 检查文件大小
if err = checkFileSize(uploadType, fileSize); err != nil {
return "", "", err
}

// 通过文件头获取类型和扩展名
mimeType, mimeExt, err := getFileTypeAndExt(file)
if err != nil {
return "", "", err
}
return mimeType, mimeExt, nil
}
// ImageLimit 图片上传大小限制
const ImageLimit = humanize.MByte * 10

// GenerateObjectKey 通过 UUID 作为文件名并生成 ObjectKey
func GenerateObjectKey(uploadType string, fileExt string) string {
return fmt.Sprintf("%s/%d/%s%s", uploadType, time.Now().Year(), uuid.NewV1().String(), fileExt)
}

// checkFileSize 检查文件大小
func checkFileSize(uploadType string, size int64) error {
maxSize, ok := uploadTypeLimits[uploadType]
if !ok {
return ErrUnsupportedUploadType
}
if size > maxSize {
return ErrSizeExceeded
}
return nil
}

// getFileTypeAndExt 根据文件头(Magic Number)判断文件类型和扩展名
func getFileTypeAndExt(file multipart.File) (mimeType string, mimeExt string, err error) {
mime, err := mimetype.DetectReader(file)
if err != nil {
return "", "", err
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return "", "", err
}
return mime.String(), mime.Extension(), nil
}

// ConvertToWebP 将图片转换为 WebP 格式
func ConvertToWebP(file multipart.File) (io.Reader, int64, error) {
img, _, err := image.Decode(file)
func ConvertToWebP(reader io.Reader) (io.Reader, int64, error) {
img, _, err := image.Decode(reader)
if err != nil {
return nil, 0, err
}
Expand Down
3 changes: 2 additions & 1 deletion app/utils/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"os"
"os/signal"
"syscall"
"time"

"4u-go/config/redis"
Expand All @@ -29,7 +30,7 @@ func Run(handler http.Handler, addr string) {

// 阻塞并监听结束信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit

zap.L().Info("Shutdown Server...")
Expand Down
2 changes: 1 addition & 1 deletion config/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func Init(r *gin.Engine) {
user.POST("/login", userController.AuthByPassword)
user.POST("/login/session", userController.AuthBySession)

user.POST("/attachment", objectController.UploadFile)
user.POST("/upload", objectController.UploadFile)

user.POST("/repass", midwares.CheckLogin, userController.ChangePassword)
user.DELETE("/delete", midwares.CheckLogin, userController.DeleteAccount)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.22.9
require (
github.com/chai2010/webp v1.1.1
github.com/dustin/go-humanize v1.0.1
github.com/gabriel-vasile/mimetype v1.4.6
github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/sessions v1.0.1
github.com/gin-gonic/gin v1.10.0
Expand Down Expand Up @@ -36,6 +35,7 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
Expand Down

0 comments on commit 71af29a

Please sign in to comment.