fix:修复上传

This commit is contained in:
Hiven 2023-08-10 15:23:28 +08:00
parent 5f1a07f737
commit 13ad52d095
4 changed files with 82 additions and 152 deletions

View File

@ -1,13 +1,9 @@
package handler package handler
import ( import (
"errors"
"net/http" "net/http"
"reflect"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/server/upload/internal/logic" "fusenapi/server/upload/internal/logic"
@ -18,72 +14,22 @@ import (
func UploadFileBackendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { func UploadFileBackendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var ( var req types.UploadFileBackendReq
// 定义错误变量 userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
err error
// 定义用户信息变量
userinfo *auth.UserInfo
)
// 解析JWT token,并对空用户进行判断
claims, err := svcCtx.ParseJwtToken(r)
// 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息
if err != nil { if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401, // 返回401状态码,表示未授权
Message: "unauthorized", // 返回未授权信息
})
logx.Info("unauthorized:", err.Error()) // 记录错误日志
return
}
if claims != nil {
// 从token中获取对应的用户信息
userinfo, err = auth.GetUserInfoFormMapClaims(claims)
// 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401,
Message: "unauthorized",
})
logx.Info("unauthorized:", err.Error())
return
}
} else {
// 如果claims为nil,则认为用户身份为白板用户
userinfo = &auth.UserInfo{UserId: 0, GuestId: 0}
}
var req types.RequestUploadFileBackend
// 如果端点有请求结构体则使用httpx.Parse方法从HTTP请求体中解析请求数据
if err := httpx.Parse(r, &req); err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 510,
Message: "parameter error",
})
logx.Info(err)
return
}
// 解析upload文件类型
err = basic.RequestFileParse(r, &req)
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 510,
Message: err.Error(),
})
return return
} }
// 创建一个业务逻辑层实例 // 创建一个业务逻辑层实例
l := logic.NewUploadFileBackendLogic(r.Context(), svcCtx) l := logic.NewUploadFileBackendLogic(r, svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UploadFileBackend(&req, userinfo) resp := l.UploadFileBackend(&req, userinfo)
// 如果响应不为nil则使用httpx.OkJsonCtx方法返回JSON响应;
if resp != nil { if !basic.AfterLogic(w, r, rl, resp) {
httpx.OkJsonCtx(r.Context(), w, resp) basic.NormalAfterLogic(w, r, resp)
} else {
err := errors.New("server logic is error, resp must not be nil")
httpx.ErrorCtx(r.Context(), w, err)
logx.Error(err)
} }
} }
} }

View File

@ -3,18 +3,16 @@ package logic
import ( import (
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/check" "fusenapi/utils/file"
"fusenapi/utils/format" "fusenapi/utils/hash"
"time" "io"
"net/http"
"context" "context"
"fusenapi/server/upload/internal/svc" "fusenapi/server/upload/internal/svc"
"fusenapi/server/upload/internal/types" "fusenapi/server/upload/internal/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -22,109 +20,91 @@ type UploadFileBackendLogic struct {
logx.Logger logx.Logger
ctx context.Context ctx context.Context
svcCtx *svc.ServiceContext svcCtx *svc.ServiceContext
r *http.Request
} }
func NewUploadFileBackendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileBackendLogic { func NewUploadFileBackendLogic(r *http.Request, svcCtx *svc.ServiceContext) *UploadFileBackendLogic {
return &UploadFileBackendLogic{ return &UploadFileBackendLogic{
Logger: logx.WithContext(ctx), Logger: logx.WithContext(r.Context()),
ctx: ctx, ctx: r.Context(),
svcCtx: svcCtx, svcCtx: svcCtx,
r: r,
} }
} }
// UploadFileBackend 这个函数接收一个文件上传请求和用户信息,处理文件上传,并返回响应 // 处理进入前逻辑w,r
func (l *UploadFileBackendLogic) UploadFileBackend(req *types.RequestUploadFileBackend, userinfo *auth.UserInfo) (resp *basic.Response) { // func (l *UploadFileBackendLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UploadFileBackendLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }
func (l *UploadFileBackendLogic) UploadFileBackend(req *types.UploadFileBackendReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
// 检查用户是否是旁观者,旁观者没有文件上传权限
if userinfo.IsOnlooker() { if userinfo.IsOnlooker() {
// 如果是,返回未授权的错误码 // 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
// 定义用户ID和S3键名格式 // 定义用户ID和S3键名格式
var uid int64 var userId int64
var keytype format.TypeFormatS3KeyName var guestId int64
// 检查用户是否是游客 // 检查用户是否是游客
if userinfo.IsGuest() { if userinfo.IsGuest() {
// 如果是使用游客ID和游客键名格式 // 如果是使用游客ID和游客键名格式
uid = userinfo.GuestId guestId = userinfo.GuestId
keytype = format.TypeS3KeyGuest
} else { } else {
// 否则使用用户ID和用户键名格式 // 否则使用用户ID和用户键名格式
uid = userinfo.UserId userId = userinfo.UserId
keytype = format.TypeS3KeyUser
} }
// 设置AWS会话的区域 //设置内存大小
l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1") l.r.ParseMultipartForm(32 << 20)
// 创建新的S3服务实例 fileObject, _, err := l.r.FormFile("file")
svc := s3.New(l.svcCtx.AwsSession)
// 检查类别是否合法
if !check.CheckCategory(req.Category) {
// 如果不合法,返回类别错误的错误码
return resp.SetStatus(basic.CodeS3CategoryErr)
}
// 定义S3请求和当前时间
var s3req *request.Request
now := time.Now()
// 格式化类别
category := format.TypeCategory(req.Category)
// 格式化S3对象键名
ObjectKey := aws.String(format.FormatS3KeyName(
keytype,
uid,
now,
l.svcCtx.Config.Env,
category,
req.File.Filename,
))
// 定义存储桶名称
var bucketName *string
// 根据类别选择存储桶
switch category {
case format.TCategoryRenderMegre:
bucketName = basic.TempfileBucketName
default:
bucketName = basic.StorageBucketName
}
// 创建S3对象存储请求
s3req, _ = svc.PutObjectRequest(
&s3.PutObjectInput{
Bucket: bucketName,
Key: ObjectKey,
},
)
// 设置请求体为文件数据
s3req.SetBufferBody(req.File.Data)
// 发送请求
err := s3req.Send()
// 检查是否有错误
if err != nil { if err != nil {
// 如果有,打印错误并返回错误码
logx.Error(err) logx.Error(err)
return resp.SetStatus(basic.CodeS3PutObjectRequestErr) return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files")
} }
// 打印请求URL // 读取数据流
logx.Info(s3req.HTTPRequest.URL.String()) ioData, err := io.ReadAll(fileObject)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files")
}
// 上传文件
var upload = file.Upload{
Ctx: l.ctx,
MysqlConn: l.svcCtx.MysqlConn,
AwsSession: l.svcCtx.AwsSession,
}
var resourceId string = hash.JsonHashKey(req.FileKey)
uploadRes, err := upload.UploadFileByByte(&file.UploadBaseReq{
FileHash: resourceId,
FileByte: ioData,
UploadBucket: req.UploadBucket,
ApiType: req.ApiType,
UserId: userId,
GuestId: guestId,
})
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeFileUploadErr, "upload file failed")
}
// 返回成功的响应和上传URL // 返回成功的响应和上传URL
return resp.SetStatus(basic.CodeOK, map[string]interface{}{ return resp.SetStatus(basic.CodeOK, map[string]interface{}{
"upload_url": s3req.HTTPRequest.URL.String(), "upload_data": UploadUrl{
Status: 1,
ResourceId: uploadRes.ResourceId,
ResourceUrl: uploadRes.ResourceUrl,
},
}) })
} }

View File

@ -23,10 +23,12 @@ type UploadLogoReq struct {
SkuId int64 `form:"sku_id,default=0"` // 模板ID SkuId int64 `form:"sku_id,default=0"` // 模板ID
} }
type UploadInfo struct { type UploadFileBackendReq struct {
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息 ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
FileKeys string `form:"file_keys,optional"` // 上传唯一标识信息 UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
Metadata string `form:"meta_data,optional"` // 上传文件额外信息 FileKey string `form:"file_key"` // 上传唯一标识信息
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
} }
type UploadFilesReq struct { type UploadFilesReq struct {

View File

@ -17,7 +17,7 @@ service upload {
post /api/upload/upload-file-frontend(RequestUploadFileFrontend) returns (response); post /api/upload/upload-file-frontend(RequestUploadFileFrontend) returns (response);
@handler UploadFileBackendHandler @handler UploadFileBackendHandler
post /api/upload/upload-file-backend(RequestUploadFileBackend) returns (response); post /api/upload/upload-file-backend(UploadFileBackendReq) returns (response);
//生成二维码 //生成二维码
@handler UploadQrcodeHandler @handler UploadQrcodeHandler
post /api/upload/qrcode(UploadQrcodeReq) returns (response); post /api/upload/qrcode(UploadQrcodeReq) returns (response);
@ -67,10 +67,12 @@ type (
) )
type ( type (
UploadInfo { UploadFileBackendReq {
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息 ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
FileKeys string `form:"file_keys,optional"` // 上传唯一标识信息 UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
Metadata string `form:"meta_data,optional"` // 上传文件额外信息 FileKey string `form:"file_key"` // 上传唯一标识信息
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
} }
UploadFilesReq { UploadFilesReq {