1. Server, Use golang.

Init minIO client.

func initMinio() *minio.Client {

 client, err := minio.New("localhost:9000",   // minio-hostname
  &minio.Options{
   Creds:  credentials.NewStaticV4("minio-user", "minio-password", ""), //minio-user, minio-password
   Secure: false,
  })
 if err != nil {
  slog.Error("Failed to connect minIO server: ", "err", err)
  panic(err)
 }

 for _, bucket := range buckets { // ["image", "audio", "video", ...]
  exists, err := client.BucketExists(context.Background(), bucket). // check bucket
  if err != nil {
   log.Fatal("Failed to check if bucket exists: ", err)
  }
  if !exists {
   err = client.MakeBucket(context.Background(), bucket, minio.MakeBucketOptions{})
   if err != nil {
    log.Fatal("Failed to create bucket: ", err)
   }
  }
 }

 return client
}

2. Presigned by minIO

func (c *Controller) PresignedByMinio(r *gin.Context) {  // 
 request := &requests.PresignedResource{} // {Bucket:"image", Suffixs:["jpeg", "png"]}
 err := r.ShouldBindJSON(request)
 if err != nil {
  c.Err(r, 901, err)
  return
 }

 arr := make([]*requests.ResourceItem, 0)
 for _, suffix := range request.Suffixs {
  url, err := c.PresignedURL(r, request.Bucket, suffix)
  if err != nil {
   c.Err(r, 903, err)
   return
  }

  it := &requests.ResourceItem{}
  it.UploadURL = url.String()
  it.RequestURL = fmt.Sprintf("%s://%s%s", url.Scheme, url.Host, url.Path)
  slog.Debug("PresignedURL", suffix, it.UploadURL)
  arr = append(arr, it)
 }
 c.OK(r, arr)
}

2. Web , use javascript

export function Resource() {
    this.uploads = []  // Upload required, element = {UploadURL: string, RequestURL: string, file: File}
    this.winners = []  // Upload successful
    this.losers = []  // Upload failed
}

Resource.prototype.uploadImage = function (files, back) {
    const suffixs = files.map((file) => file.name.split(".").pop())
    this.presigned("image", suffixs, files, back) 
}

Resource.prototype.presigned = function (bucket, suffixs, files, back) {
    API.resourcePresigned.request("POST", { bucket: bucket, suffixs: suffixs }).then((result) => {
        if (result.Succeed) {
            const uploads = result.Data
            if (!uploads || uploads.length != files.length) {
                back([], [], "上传失败")
                return
            }
            files.forEach((element, index) => {
                uploads[index].file = element
            });
            this.uploads = uploads
            this.upload(back)
        } else {
            back([], [], result.message)
        }
    })
}

Resource.prototype.upload = function (back) {
    if (this.uploads.length === 0) {
        back(this.winners, this.losers, "上传成功")
        return
    }
    let item = this.uploads.shift()
    if (!item.file) {
        this.losers.push(item)
        this.upload(back)
        return
    }
    item.uploadURL.put(item.file).then((result) => {
        if (result.Succeed) {
            this.winners.push(item)
        } else {
            this.losers.push(item)
        }
        this.upload(back)
    })
}