From 80d57ed8f942060062691663e46c6166010fffbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=BA=E6=97=BA=E7=A2=8E=E5=86=B0=E5=86=B0?= <38837039+Cyberhan123@users.noreply.github.com> Date: Tue, 14 Mar 2023 09:57:22 +0800 Subject: [PATCH] add postForm with multi data content type support (#2508) --- net/gclient/gclient_request.go | 43 ++++++++++++++++++------------ net/gclient/gclient_z_unit_test.go | 9 ++++++- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/net/gclient/gclient_request.go b/net/gclient/gclient_request.go index c1df03ea7..cfc1629f7 100644 --- a/net/gclient/gclient_request.go +++ b/net/gclient/gclient_request.go @@ -13,7 +13,6 @@ import ( "io/ioutil" "mime/multipart" "net/http" - "net/url" "os" "strings" "time" @@ -84,26 +83,36 @@ func (c *Client) Trace(ctx context.Context, url string, data ...interface{}) (*R return c.DoRequest(ctx, http.MethodTrace, url, data...) } -// PostForm issues a POST to the specified URL, -// with data's keys and values URL-encoded as the request body. +// PostForm is different from net/http.PostForm. +// It's a wrapper of Post method, which sets the Content-Type as "multipart/form-data;". +// and It will automatically set boundary characters for the request body and Content-Type. // -// The Content-Type header is set to application/x-www-form-urlencoded. -// To set other headers, use NewRequest and Client.Do. +// It's Seem like the following case: // -// When err is nil, resp always contains a non-nil resp.Body. -// Caller should close resp.Body when done reading from it. +// Content-Type: multipart/form-data; boundary=----Boundarye4Ghaog6giyQ9ncN // -// See the Client.Do method documentation for details on how redirects -// are handled. +// And form data is like: +// ------Boundarye4Ghaog6giyQ9ncN +// Content-Disposition: form-data; name="checkType" // -// To make a request with a specified context.Context, use NewRequestWithContext -// and Client.Do. -// Deprecated: use Post instead. -func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) { - return nil, gerror.NewCode( - gcode.CodeNotSupported, - `PostForm is not supported, please use Post instead`, - ) +// none +// +// It's used for sending form data. +// Note that the response object MUST be closed if it'll never be used. +func (c *Client) PostForm(ctx context.Context, url string, data map[string]string) (resp *Response, err error) { + body := new(bytes.Buffer) + w := multipart.NewWriter(body) + for k, v := range data { + err := w.WriteField(k, v) + if err != nil { + return nil, err + } + } + err = w.Close() + if err != nil { + return nil, err + } + return c.ContentType(w.FormDataContentType()).Post(ctx, url, body) } // DoRequest sends request with given HTTP method and data and returns the response object. diff --git a/net/gclient/gclient_z_unit_test.go b/net/gclient/gclient_z_unit_test.go index 66ee46038..d0be46b02 100644 --- a/net/gclient/gclient_z_unit_test.go +++ b/net/gclient/gclient_z_unit_test.go @@ -38,6 +38,9 @@ func Test_Client_Basic(t *testing.T) { s.BindHandler("/hello", func(r *ghttp.Request) { r.Response.Write("hello") }) + s.BindHandler("/postForm", func(r *ghttp.Request) { + r.Response.Write(r.Get("key1")) + }) s.SetDumpRouterMap(false) s.Start() defer s.Shutdown() @@ -54,8 +57,12 @@ func Test_Client_Basic(t *testing.T) { _, err := g.Client().Post(ctx, "") t.AssertNE(err, nil) - _, err = g.Client().PostForm("", nil) + _, err = g.Client().PostForm(ctx, "/postForm", nil) t.AssertNE(err, nil) + data, _ := g.Client().PostForm(ctx, url+"/postForm", map[string]string{ + "key1": "value1", + }) + t.Assert(data.ReadAllString(), "value1") }) }