From 0d99a2c8c7f2c1c1817b59bdcf5ceaa6cec2160e Mon Sep 17 00:00:00 2001 From: guonaihong Date: Mon, 6 Mar 2023 22:52:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9ESetHeaderRaw=20(#362)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 52 +++++++++++++++++++++++++++++++- dataflow/dataflow.go | 7 +++++ dataflow/dataflow_header_test.go | 40 ++++++++++++++++++++++-- dataflow/req.go | 5 ++- encode/encode_core_test.go | 6 ++-- encode/header.go | 15 ++++++--- encode/header_test.go | 9 +++--- encode/www_form_test.go | 20 ++++++++++++ 9 files changed, 139 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 52b943a..cbee210 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.dll *.so *.dylib +/cover.cov .DS_Store .idea diff --git a/README.md b/README.md index ea203b1..9874c27 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ gout 是go写的http 客户端,为提高工作效率而开发 - [GET POST PUT DELETE PATH HEAD OPTIONS template](#get-post-put-delete-path-head-options-template) - [Query Parameters](#Query-Parameters) - [http header](#http-header) + - [Do not convert http headers](#do-not-convert-http-headers) - [Set request header](#set-request-header) - [Parsing the response header](#parsing-the-response-header) - [get all header](#get-all-header) @@ -348,7 +349,6 @@ func main() { ``` ### SetQuery支持的更多数据类型 -
```go package main @@ -412,6 +412,56 @@ SetQuery([]string{"active", "enable", "action", "drop"})`
## http header +#### Do not convert http headers +与SetHeader API唯一的区别就是不修改header名. 大部分情况用SetHeader,如果有不修改header的需求再使用SetHeaderRaw。 +```go +package main + +import ( + "fmt" + "github.com/guonaihong/gout" + "time" +) + +func main() { + err := gout. + //设置GET请求和url,:8080/test.header是127.0.0.1:8080/test.header的简写 + GET(":8080/test.header"). + //设置debug模式 + Debug(true). + //设置请求http header + SetHeaderRaw(gout.H{ + "h1": "v1", + "h2": 2, + "h3": float32(3.14), + "h4": 4.56, + "h5": time.Now().Unix(), + "h6": time.Now().UnixNano(), + "h7": time.Now().Format("2006-01-02")}). + Do() + if err != nil { + fmt.Printf("%s\n", err) + return + } + +} + +/* +> GET /test.header HTTP/1.1 +> h2: 2 +> h3: 3.14 +> h4: 4.56 +> h5: 1574081686 +> h6: 1574081686471347098 +> h7: 2019-11-18 +> h1: v1 +> + + +< HTTP/1.1 200 OK +< Content-Length: 0 +*/ +``` #### Set request header ```go package main diff --git a/dataflow/dataflow.go b/dataflow/dataflow.go index 04ea630..d31c621 100644 --- a/dataflow/dataflow.go +++ b/dataflow/dataflow.go @@ -180,6 +180,13 @@ func (df *DataFlow) SetHeader(obj ...interface{}) *DataFlow { return df } +// SetHeader send http header, Support struct/map/slice types +func (df *DataFlow) SetHeaderRaw(obj ...interface{}) *DataFlow { + df.Req.headerEncode = append([]interface{}{}, obj...) + df.Req.rawHeader = true + return df +} + // SetJSON send json to the http body, Support raw json(string, []byte)/struct/map types func (df *DataFlow) SetJSON(obj interface{}) *DataFlow { df.ReqBodyType = "json" diff --git a/dataflow/dataflow_header_test.go b/dataflow/dataflow_header_test.go index 43cf072..b1c65f6 100644 --- a/dataflow/dataflow_header_test.go +++ b/dataflow/dataflow_header_test.go @@ -1,13 +1,14 @@ package dataflow import ( - "github.com/gin-gonic/gin" - "github.com/guonaihong/gout/core" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" "time" + + "github.com/gin-gonic/gin" + "github.com/guonaihong/gout/core" + "github.com/stretchr/testify/assert" ) type testHeader2 struct { @@ -177,3 +178,36 @@ func Test_BindHeader_empty(t *testing.T) { assert.Equal(t, tHeader.Sid, "sid-ok") } } + +// 测试直接发送raw http header。 +func Test_HeaderRaw(t *testing.T) { + router := func() *gin.Engine { + router := gin.New() + + router.GET("/test.header", func(c *gin.Context) { + h := map[string][]string(c.Request.Header) + c.Writer.Header().Add("sid", h["Sid"][0]) + }) + + return router + }() + + ts := httptest.NewServer(http.HandlerFunc(router.ServeHTTP)) + + g := New() + + type testHeader2 struct { + Sid string `header:"sid"` + Code int + } + + var tHeader testHeader2 + for _, v := range []interface{}{ + core.A{"sid", "hello"}, + } { + err := g.GET(ts.URL + "/test.header").Debug(true).SetHeaderRaw(v).BindHeader(&tHeader).Code(&tHeader.Code).Do() + assert.NoError(t, err) + assert.Equal(t, tHeader.Code, 200) + assert.Equal(t, tHeader.Sid, "hello") + } +} diff --git a/dataflow/req.go b/dataflow/req.go index 780567e..b47d6ce 100644 --- a/dataflow/req.go +++ b/dataflow/req.go @@ -38,6 +38,9 @@ type Req struct { // http header headerEncode []interface{} + // raw header + rawHeader bool + headerDecode interface{} // query @@ -349,7 +352,7 @@ func (r *Req) encodeHeader(req *http.Request) (err error) { continue } - err = encode.Encode(h, encode.NewHeaderEncode(req)) + err = encode.Encode(h, encode.NewHeaderEncode(req, r.rawHeader)) if err != nil { return err } diff --git a/encode/encode_core_test.go b/encode/encode_core_test.go index 52c7b6f..6590ee0 100644 --- a/encode/encode_core_test.go +++ b/encode/encode_core_test.go @@ -35,7 +35,7 @@ func testEncodeCore_Encode(t *testing.T) { assert.NoError(t, err) for _, v := range testPtr { - err := Encode(v.set, NewHeaderEncode(req)) + err := Encode(v.set, NewHeaderEncode(req, false)) assert.NoError(t, err) } } @@ -60,7 +60,7 @@ func testEncodeCore_Encode_Fail(t *testing.T) { assert.NoError(t, err) for _, v := range testFail { - err := Encode(v.set, NewHeaderEncode(req)) + err := Encode(v.set, NewHeaderEncode(req, false)) assert.Error(t, err) } @@ -143,7 +143,7 @@ func TestEncodeCore_parseTagAndSet(t *testing.T) { for _, v := range test { val := reflect.ValueOf(v.set) - err := parseTagAndSet(val.Field(0), val.Type().Field(0), NewHeaderEncode(&http.Request{})) + err := parseTagAndSet(val.Field(0), val.Type().Field(0), NewHeaderEncode(&http.Request{}, false)) assert.NoError(t, err) } } diff --git a/encode/header.go b/encode/header.go index 1cd049a..33bc030 100644 --- a/encode/header.go +++ b/encode/header.go @@ -9,17 +9,24 @@ var _ Adder = (*HeaderEncode)(nil) // HeaderEncode http header encoder structure type HeaderEncode struct { - r *http.Request + r *http.Request + rawHeader bool } // NewHeaderEncode create a new http header encoder -func NewHeaderEncode(req *http.Request) *HeaderEncode { - return &HeaderEncode{r: req} +func NewHeaderEncode(req *http.Request, rawHeader bool) *HeaderEncode { + return &HeaderEncode{r: req, rawHeader: rawHeader} } // Add Encoder core function, used to set each key / value into the http header func (h *HeaderEncode) Add(key string, v reflect.Value, sf reflect.StructField) error { - h.r.Header.Add(key, valToStr(v, sf)) + value := valToStr(v, sf) + if !h.rawHeader { + h.r.Header.Add(key, value) + } else { + + h.r.Header[key] = append(h.r.Header[key], value) + } return nil } diff --git a/encode/header_test.go b/encode/header_test.go index bc3e9f7..9ba1d4c 100644 --- a/encode/header_test.go +++ b/encode/header_test.go @@ -2,9 +2,10 @@ package encode import ( "fmt" - "github.com/stretchr/testify/assert" "net/http" "testing" + + "github.com/stretchr/testify/assert" ) type testH map[string]interface{} @@ -16,7 +17,7 @@ func TestHeaderStringSlice(t *testing.T) { "header1", "value1", "header2", "value2", "header3", "value3", - }, NewHeaderEncode(req)) + }, NewHeaderEncode(req, false)) assert.NoError(t, err) @@ -36,7 +37,7 @@ func TestHeaderMap(t *testing.T) { "header1": 1, "header2": "value2", "header3": 3.14, - }, NewHeaderEncode(req)) + }, NewHeaderEncode(req, false)) assert.NoError(t, err) @@ -83,7 +84,7 @@ func TestHeaderStruct(t *testing.T) { }, H: &p, }, - NewHeaderEncode(req), + NewHeaderEncode(req, false), ) assert.NoError(t, err) diff --git a/encode/www_form_test.go b/encode/www_form_test.go index 207e01a..13c069e 100644 --- a/encode/www_form_test.go +++ b/encode/www_form_test.go @@ -35,3 +35,23 @@ func Test_WWWForm_Encode(t *testing.T) { func Test_WWWForm_Name(t *testing.T) { assert.Equal(t, NewWWWFormEncode(setting.Setting{}).Name(), "www-form") } + +type CreateUserMetadataReqBody struct { + Avatarurl string `www-form:"avatarurl"` + Nickname string `www-form:"nickname"` +} + +func Test_WWWForm_Struct(t *testing.T) { + + data := CreateUserMetadataReqBody{Avatarurl: "www.hh.com", Nickname: "good"} + enc := NewWWWFormEncode(setting.Setting{}) + err := enc.Encode(&data) + assert.NoError(t, err) + + var out bytes.Buffer + assert.NoError(t, enc.End(&out)) + pos := bytes.Index(out.Bytes(), []byte("avatarurl")) + pos1 := bytes.Index(out.Bytes(), []byte("nickname")) + assert.NotEqual(t, pos, -1) + assert.NotEqual(t, pos1, -1) +}