resty icon indicating copy to clipboard operation
resty copied to clipboard

Multipart file upload name parameter is not configurable

Open TLINDEN opened this issue 2 years ago • 4 comments

If you upload multiple files resty sets the name= form-data parameter to the filename of each file, e.g. when uploading 2 files, xxx and yyy:

~~~ REQUEST ~~~
POST  /api/putfile  HTTP/1.1
HOST   : localhost:8080
HEADERS:
        Content-Type: multipart/form-data; boundary=816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
        User-Agent: go-resty/2.7.0 (https://github.com/go-resty/resty)
BODY   :
--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="yyy"; filename="yyy"
Content-Type: application/octet-stream

Mon Feb 20 07:48:40 PM CET 2023

--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="xxx"; filename="xxx"
Content-Type: application/octet-stream

Fri Feb 17 01:00:11 PM CET 2023

--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="expire"

1d
--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4--

The problem is, I am using GIN on the receiving end and want to fetch all the uploaded files, which is currently not possible because there's no array with a shared name parameter.

Here's how such a request should look if done right, using:

curl -X POST localhost:8080/api/putfile -F "upload[]=@xxx" -F "upload[]=@yyy" -H "Content-Type: multipart/form-data"

posted content:

POST /api/putfile HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 416
Content-Type: multipart/form-data; boundary=------------------------93a472d0d0bc7413

--------------------------93a472d0d0bc7413
Content-Disposition: form-data; name="upload[]"; filename="xxx"
Content-Type: application/octet-stream

Fri Feb 17 01:00:11 PM CET 2023

--------------------------93a472d0d0bc7413
Content-Disposition: form-data; name="upload[]"; filename="yyy"
Content-Type: application/octet-stream

Mon Feb 20 07:48:40 PM CET 2023

--------------------------93a472d0d0bc7413--

It is possible to circumnavigate this issue by manually populating the form data using SetMultipartFields. But this is a tedious job, which resty already does very well- in fact that's one of the very reasons I'm trying to use it.

So, a method to set this name to a unique array over all uploaded files is required, something like SetFormDataName which then must set this parameter and append []. At least this would help me a lot!

TLINDEN avatar Feb 20 '23 19:02 TLINDEN

@TLINDEN Thanks for reaching out. I think I'm able to follow, still didn't get a full understanding. Could you please provide test case to demonstrate your use case/issue (client side and server side)?

jeevatkm avatar Mar 06 '23 05:03 jeevatkm

Yeah, this is (better: was, 'cause in the meantime I switched to another module) the client code:

package lib

import (
        "encoding/json"
        "fmt"
        "github.com/go-resty/resty/v2"
        "os"
        "path/filepath"
)

type Response struct {
        Code    int    `json:"code"`
        Success bool   `json:"success"`
        Message string `json:"message"`
}

func Runclient(cfg *cfg.Config, args []string) error {
        client := resty.New()
        client.SetDebug(cfg.Debug)

        url := cfg.Endpoint + "/putfile"

        files := os.Args[1:]
        postfiles := make(map[string]string)

        for _, file := range files {
                postfiles[filepath.Base(file)] = file
        }

        resp, err := client.R().
                SetFiles(postfiles).
                SetFormData(map[string]string{"expire": "1d"}).
                Post(url)

        if cfg.Debug {
                fmt.Println("Response Info:")
                fmt.Println("  Error      :", err)
                fmt.Println("  Status Code:", resp.StatusCode())
                fmt.Println("  Status     :", resp.Status())
                fmt.Println("  Proto      :", resp.Proto())
                fmt.Println("  Time       :", resp.Time())
                fmt.Println("  Received At:", resp.ReceivedAt())
                fmt.Println("  Body       :\n", resp)
                fmt.Println()
        }

        r := Response{}

        json.Unmarshal([]byte(resp.String()), &r)

        fmt.Println(r)
}

Serverside code is here

TLINDEN avatar Mar 06 '23 07:03 TLINDEN

@TLINDEN Thanks for sharing the code snippet. I will have a look and try to understand the context of the issue.

jeevatkm avatar Mar 08 '23 04:03 jeevatkm

如果您上传了多个文件,resty 将 form-data 参数设置为每个文件的文件名,例如在上传 2 个文件时,并且:name=``xxx``yyy

~~~ REQUEST ~~~
POST  /api/putfile  HTTP/1.1
HOST   : localhost:8080
HEADERS:
        Content-Type: multipart/form-data; boundary=816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
        User-Agent: go-resty/2.7.0 (https://github.com/go-resty/resty)
BODY   :
--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="yyy"; filename="yyy"
Content-Type: application/octet-stream

Mon Feb 20 07:48:40 PM CET 2023

--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="xxx"; filename="xxx"
Content-Type: application/octet-stream

Fri Feb 17 01:00:11 PM CET 2023

--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4
Content-Disposition: form-data; name="expire"

1d
--816c85ff0952ec600652e0d86e3f22b74386606efe95028accd9b995e1f4--

问题是,我在接收端使用 GIN 并想获取所有上传的文件,这目前是不可能的,因为没有带有共享名称参数的数组。

如果操作得当,此类请求应如下所示,使用:

curl -X POST localhost:8080/api/putfile -F "upload[]=@xxx" -F "upload[]=@yyy" -H "Content-Type: multipart/form-data"

发布内容:

POST /api/putfile HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 416
Content-Type: multipart/form-data; boundary=------------------------93a472d0d0bc7413

--------------------------93a472d0d0bc7413
Content-Disposition: form-data; name="upload[]"; filename="xxx"
Content-Type: application/octet-stream

Fri Feb 17 01:00:11 PM CET 2023

--------------------------93a472d0d0bc7413
Content-Disposition: form-data; name="upload[]"; filename="yyy"
Content-Type: application/octet-stream

Mon Feb 20 07:48:40 PM CET 2023

--------------------------93a472d0d0bc7413--

可以通过使用 手动填充表单数据来规避此问题。但这是一项乏味的工作,resty 已经做得很好了——事实上,这也是我尝试使用它的原因之一。SetMultipartFields

因此,需要一种方法来将此名称设置为所有上传文件的唯一数组,例如必须设置此参数并附加 .至少这会对我有很大帮助!SetFormDataName``[]

this can help you : https://github.com/gospider007/requests/blob/master/test/request/file_test.go

gospider007 avatar Nov 15 '23 02:11 gospider007