Go语言Docker容器内文件上传首次失败二次成功问题求助
问题分析与解决方案
核心错误原因
你的代码存在逻辑错误:在通过c.BindJSON(&body)解析完请求体后,又尝试从c.Request.Body读取数据上传,但此时请求体已经被BindJSON读取完毕,导致上传的是空内容,这就是首次上传失败的根本原因。
本地Docker或直接服务器运行时看似正常,大概率是因为环境差异(比如部分环境隐式支持请求体重复读取),但这属于偶然情况,并非代码本身正确。
修正后的代码
将上传逻辑改为使用Base64解码后的decoded数据,而非已被读取的请求体:
func UploadFile() gin.HandlerFunc { return func(c *gin.Context) { var body settings.BodyContent if err := c.BindJSON(&body); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"message": "Internal error", "success": false}) return } // 建议全局初始化Minio客户端,避免每次请求创建 cdn, err := minio.New("cdn.hahu.jobs", &minio.Options{ Creds: credentials.NewStaticV4(settings.MINIO_ACCESS_KEY, settings.MINIO_SECRET_KEY, ""), Secure: true, }) if err != nil { log.Println("Auth error :: ", err) c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), "success": false, }) return } // 用更安全的方式处理路径后缀 if !strings.HasSuffix(body.Input.Folder, "/") { body.Input.Folder += "/" } body.Input.Folder = path.Join("bridges", body.Input.Folder) urls := []string{} secure_urls := []string{} for i := range body.Input.Files { file := body.Input.Files[i] parts := strings.Split(file, ",") // 校验Base64格式合法性 if len(parts) < 2 { c.JSON(http.StatusBadRequest, gin.H{ "message": "Invalid Base64 format", "success": false, }) return } fileBase64 := parts[1] decoded, err := base64.StdEncoding.DecodeString(fileBase64) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), "success": false, }) return } kind, err := filetype.Match(decoded) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), "success": false, }) return } id := path.Join(body.Input.Folder, randstr.Hex(50)) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // 使用Base64解码后的真实数据上传 _, err = cdn.PutObject(ctx, "public", id, bytes.NewReader(decoded), int64(len(decoded)), minio.PutObjectOptions{ ContentType: kind.MIME.Value, }) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), "success": false, }) return } url := fmt.Sprintf("http://cdn.hahu.jobs/public/%s", id) secure_url := fmt.Sprintf("https://cdn.hahu.jobs/public/%s", id) urls = append(urls, url) secure_urls = append(secure_urls, secure_url) // 只处理一个文件 break } c.JSON(http.StatusOK, gin.H{ "urls": urls, "secure_urls": secure_urls, }) } }
额外优化建议
- 全局初始化Minio客户端:每次请求创建客户端会消耗资源,建议在程序启动时初始化一次,全局复用。
- 路径处理用
path.Join:避免手动拼接路径出现的分隔符不一致问题。 - Base64格式校验:增加对分割结果长度的判断,避免非法格式导致程序崩溃。
- 明确文件大小:上传时传入
int64(len(decoded))而非-1,让Minio更高效处理请求。
内容的提问来源于stack exchange,提问作者Solomon Sitotaw
相关产品推荐
相关产品推荐

