From 1cf83b341aa5eaff84b2e0bae349a68f81ae68f7 Mon Sep 17 00:00:00 2001 From: violapioggia <2604296771@qq.com> Date: Wed, 8 May 2024 21:32:51 +0800 Subject: [PATCH 01/15] feat: initialize client && request --- client.go | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 26 +++++++++++ go.sum | 87 ++++++++++++++++++++++++++++++++++++ request.go | 27 +++++++++++ 4 files changed, 269 insertions(+) create mode 100644 client.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 request.go diff --git a/client.go b/client.go new file mode 100644 index 0000000..0134735 --- /dev/null +++ b/client.go @@ -0,0 +1,129 @@ +package eazy_http + +import ( + "github.com/cloudwego/hertz/pkg/app/client" + "net/http" + "net/url" +) + +type Client struct { + QueryParam url.Values + PathParams map[string]string + Header http.Header + Cookies []*http.Cookie + + client *client.Client +} + +func New() *Client { + c, _ := client.NewClient() + return &Client{client: c} +} + +func NewWithHertzClient(c *client.Client) *Client { + return createClient(c) +} + +func createClient(c *client.Client) *Client { + return &Client{client: c} +} + +func (c *Client) SetQueryParam(param, value string) *Client { + c.QueryParam.Set(param, value) + return c +} + +func (c *Client) SetQueryParams(params map[string]string) *Client { + for k, v := range params { + c.QueryParam.Set(k, v) + } + return c +} + +func (c *Client) SetQueryParamsFromValues(params url.Values) *Client { + for k, v := range params { + for _, v1 := range v { + c.QueryParam.Add(k, v1) + } + } + return c +} + +func (c *Client) SetQueryString(query string) *Client { + + return c +} + +func (c *Client) AddQueryParam(param, value string) *Client { + c.QueryParam.Add(param, value) + return c +} + +func (c *Client) AddQueryParams(params map[string]string) *Client { + for k, v := range params { + c.QueryParam.Add(k, v) + } + return c +} + +func (c *Client) SetPathParam(param, value string) *Client { + c.PathParams[param] = value + return c +} + +func (c *Client) SetPathParams(params map[string]string) *Client { + for k, v := range params { + c.PathParams[k] = v + } + return c +} + +func (c *Client) SetHeader(header, value string) *Client { + c.Header.Set(header, value) + return c +} + +func (c *Client) SetHeaders(headers map[string]string) *Client { + for k, v := range headers { + c.Header.Set(k, v) + } + return c +} + +func (c *Client) AddHeader(header, value string) *Client { + c.Header.Add(header, value) + return c +} + +func (c *Client) AddHeaders(headers map[string]string) *Client { + for k, v := range headers { + c.Header.Add(k, v) + } + return c +} + +func (c *Client) SetCookie(hc *http.Cookie) *Client { + c.Cookies = append(c.Cookies, hc) + return c +} + +func (c *Client) SetCookies(hcs []*http.Cookie) *Client { + c.Cookies = append(c.Cookies, hcs...) + return c +} + +func (c *Client) R() *Request { + r := &Request{ + QueryParam: url.Values{}, + Header: http.Header{}, + Cookies: make([]*http.Cookie, 0), + PathParams: map[string]string{}, + + client: c, + } + return r +} + +func (c *Client) NewRequest() *Request { + return c.R() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..63ffc84 --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module github.com/hertz-contrib/easy_http + +go 1.19 + +require github.com/cloudwego/hertz v0.8.1 + +require ( + github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect + github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect + github.com/bytedance/sonic v1.8.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudwego/netpoll v0.5.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + google.golang.org/protobuf v1.27.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..36f7131 --- /dev/null +++ b/go.sum @@ -0,0 +1,87 @@ +github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= +github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= +github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM= +github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= +github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= +github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4= +github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/cloudwego/hertz v0.8.1 h1:3Upzd9o5yNPz6rLx70J5xpo5emosKNkmwW00WgQhf/0= +github.com/cloudwego/hertz v0.8.1/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= +github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= +github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= +github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= +github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/request.go b/request.go new file mode 100644 index 0000000..f40a16d --- /dev/null +++ b/request.go @@ -0,0 +1,27 @@ +package eazy_http + +import ( + "context" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/protocol" + "net/http" + "net/url" +) + +type Request struct { + client *Client + Url string + Method string + QueryParam url.Values + Header http.Header + Cookies []*http.Cookie + PathParams map[string]string + FormParams map[string]string + FileParams map[string]string + BodyParams interface{} + RawRequest *protocol.Request + Ctx context.Context + RequestOptions []config.RequestOption + Result interface{} + Error interface{} +} From 61c4c00870a1cb427f89ebebbd38f8af63f3b367 Mon Sep 17 00:00:00 2001 From: violapioggia <2604296771@qq.com> Date: Wed, 8 May 2024 21:42:42 +0800 Subject: [PATCH 02/15] style: gofumpt --- client.go | 4 ++-- request.go | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 0134735..ca8679a 100644 --- a/client.go +++ b/client.go @@ -1,9 +1,10 @@ package eazy_http import ( - "github.com/cloudwego/hertz/pkg/app/client" "net/http" "net/url" + + "github.com/cloudwego/hertz/pkg/app/client" ) type Client struct { @@ -50,7 +51,6 @@ func (c *Client) SetQueryParamsFromValues(params url.Values) *Client { } func (c *Client) SetQueryString(query string) *Client { - return c } diff --git a/request.go b/request.go index f40a16d..fc4ddf7 100644 --- a/request.go +++ b/request.go @@ -2,10 +2,11 @@ package eazy_http import ( "context" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/protocol" "net/http" "net/url" + + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/protocol" ) type Request struct { From 5641152c2cc192ade865d54c984b4b16bc970efb Mon Sep 17 00:00:00 2001 From: violapioggia <2604296771@qq.com> Date: Wed, 8 May 2024 21:45:49 +0800 Subject: [PATCH 03/15] chore: add license header --- client.go | 16 ++++++++++++++++ request.go | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/client.go b/client.go index ca8679a..2e72edc 100644 --- a/client.go +++ b/client.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package eazy_http import ( diff --git a/request.go b/request.go index fc4ddf7..26db5e9 100644 --- a/request.go +++ b/request.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package eazy_http import ( From f7ac4a6f90aa0bd76a3a5e8d96dcf4733b7ad944 Mon Sep 17 00:00:00 2001 From: violapioggia Date: Sat, 11 May 2024 10:48:41 +0800 Subject: [PATCH 04/15] chore: change package name --- client.go | 2 +- request.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 2e72edc..c67f1ef 100644 --- a/client.go +++ b/client.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package eazy_http +package easy_http import ( "net/http" diff --git a/request.go b/request.go index 26db5e9..20a1b5e 100644 --- a/request.go +++ b/request.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package eazy_http +package easy_http import ( "context" From 3c452811edaff424432370dab2a6488597d93819 Mon Sep 17 00:00:00 2001 From: violapioggia Date: Tue, 14 May 2024 23:44:57 +0800 Subject: [PATCH 05/15] feat: add response --- client.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++---- easy_http.go | 36 ++++++++++++++ middleware.go | 17 +++++++ request.go | 2 + response.go | 88 ++++++++++++++++++++++++++++++++++ 5 files changed, 264 insertions(+), 8 deletions(-) create mode 100644 easy_http.go create mode 100644 middleware.go create mode 100644 response.go diff --git a/client.go b/client.go index c67f1ef..daea7f3 100644 --- a/client.go +++ b/client.go @@ -17,8 +17,12 @@ package easy_http import ( + "context" + "github.com/cloudwego/hertz/pkg/protocol" "net/http" "net/url" + "sync" + "time" "github.com/cloudwego/hertz/pkg/app/client" ) @@ -29,17 +33,19 @@ type Client struct { Header http.Header Cookies []*http.Cookie - client *client.Client -} + beforeRequest []RequestMiddleware + udBeforeRequest []RequestMiddleware + afterResponse []ResponseMiddleware + afterResponseLock *sync.RWMutex + udBeforeRequestLock *sync.RWMutex -func New() *Client { - c, _ := client.NewClient() - return &Client{client: c} + client *client.Client } -func NewWithHertzClient(c *client.Client) *Client { - return createClient(c) -} +type ( + RequestMiddleware func(*Client, *Request) error + ResponseMiddleware func(*Client, *Response) error +) func createClient(c *client.Client) *Client { return &Client{client: c} @@ -67,6 +73,7 @@ func (c *Client) SetQueryParamsFromValues(params url.Values) *Client { } func (c *Client) SetQueryString(query string) *Client { + // todo: parse query string return c } @@ -106,6 +113,15 @@ func (c *Client) SetHeaders(headers map[string]string) *Client { return c } +func (c *Client) SetHeaderMultiValues(headers map[string][]string) *Client { + for k, header := range headers { + for _, v := range header { + c.Header.Set(k, v) + } + } + return c +} + func (c *Client) AddHeader(header, value string) *Client { c.Header.Add(header, value) return c @@ -118,6 +134,46 @@ func (c *Client) AddHeaders(headers map[string]string) *Client { return c } +func (c *Client) AddHeaderMultiValues(headers map[string][]string) *Client { + for k, header := range headers { + for _, v := range header { + c.Header.Add(k, v) + } + } + return c +} + +func (c *Client) SetContentType(contentType string) *Client { + c.Header.Set("Content-Type", contentType) + return c +} + +func (c *Client) SetJSONContentType() *Client { + c.Header.Set("Content-Type", "application/json") + return c +} + +func (c *Client) SetXMLContentType() *Client { + c.Header.Set("Content-Type", "application/xml") + return c +} + +func (c *Client) SetHTMLContentType() *Client { + c.Header.Set("Content-Type", "text/html") + return c +} + +func (c *Client) SetFormContentType() *Client { + c.Header.Set("Content-Type", "application/x-www-form-urlencoded") + return c + +} + +func (c *Client) SetXFormData() *Client { + c.Header.Set("Content-Type", "multipart/form-data") + return c +} + func (c *Client) SetCookie(hc *http.Cookie) *Client { c.Cookies = append(c.Cookies, hc) return c @@ -143,3 +199,60 @@ func (c *Client) R() *Request { func (c *Client) NewRequest() *Request { return c.R() } + +func (c *Client) execute(req *Request) (*Response, error) { + // Lock the user-defined pre-request hooks. + c.udBeforeRequestLock.RLock() + defer c.udBeforeRequestLock.RUnlock() + + // Lock the post-request hooks. + c.afterResponseLock.RLock() + defer c.afterResponseLock.RUnlock() + + // Apply Request middleware + var err error + + // user defined on before request methods + // to modify the *resty.Request object + for _, f := range c.udBeforeRequest { + if err = f(c, req); err != nil { + return nil, err + } + } + + for _, f := range c.beforeRequest { + if err = f(c, req); err != nil { + return nil, err + } + } + + if hostHeader := req.Header.Get("Host"); hostHeader != "" { + req.RawRequest.SetHost(hostHeader) + } + + req.Time = time.Now() + + resp := &protocol.Response{} + err = c.client.Do(context.Background(), req.RawRequest, resp) + + response := &Response{ + Request: req, + RawResponse: resp, + } + + if err != nil { + response.receiveAt = time.Now() + return response, err + } + + response.receiveAt = time.Now() + + // Apply Response middleware + for _, f := range c.afterResponse { + if err = f(c, response); err != nil { + break + } + } + + return response, err +} diff --git a/easy_http.go b/easy_http.go new file mode 100644 index 0000000..ff1fc86 --- /dev/null +++ b/easy_http.go @@ -0,0 +1,36 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package easy_http + +import "github.com/cloudwego/hertz/pkg/app/client" + +func New() (*Client, error) { + c, err := client.NewClient() + return &Client{client: c}, err +} + +func MustNew() *Client { + c, err := client.NewClient() + if err != nil { + panic(err) + } + return &Client{client: c} +} + +func NewWithHertzClient(c *client.Client) *Client { + return createClient(c) +} diff --git a/middleware.go b/middleware.go new file mode 100644 index 0000000..3a3909d --- /dev/null +++ b/middleware.go @@ -0,0 +1,17 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package easy_http diff --git a/request.go b/request.go index 20a1b5e..8fb91d5 100644 --- a/request.go +++ b/request.go @@ -20,6 +20,7 @@ import ( "context" "net/http" "net/url" + "time" "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/protocol" @@ -37,6 +38,7 @@ type Request struct { FileParams map[string]string BodyParams interface{} RawRequest *protocol.Request + Time time.Time Ctx context.Context RequestOptions []config.RequestOption Result interface{} diff --git a/response.go b/response.go new file mode 100644 index 0000000..820074b --- /dev/null +++ b/response.go @@ -0,0 +1,88 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package easy_http + +import ( + "github.com/cloudwego/hertz/pkg/protocol" + "strings" + "time" +) + +type Response struct { + Request *Request // 上面的 Request 结构体 + RawResponse *protocol.Response + + receiveAt time.Time + + bodyByte []byte + size int64 +} + +func (r *Response) Body() []byte { + if r.RawResponse == nil { + return []byte{} + } + return r.bodyByte +} + +func (r *Response) BodyString() string { + if r.RawResponse == nil { + return "" + } + return strings.TrimSpace(string(r.bodyByte)) +} + +func (r *Response) StatusCode() int { + if r.RawResponse == nil { + return 0 + } + return r.RawResponse.StatusCode() +} + +func (r *Response) Result() interface{} { + return r.Request.Result +} + +func (r *Response) Error() interface{} { + return r.Request.Error +} + +// todo +//func (r *Response) Header() http.Header { +// if r.RawResponse == nil { +// return http.Header{} +// } +// return r.RawResponse.Header.GetHeaders() +//} +// +//func (r *Response) Cookies() []*http.Cookie { +// if r.RawResponse == nil { +// return make([]*http.Cookie, 0) +// } +// return r.RawResponse.Header.GetCookies() +//} +//func (r *Response) ToRawHTTPResponse() string { +// return r.RawResponse.String() +//} + +func (r *Response) IsSuccess() bool { + return r.StatusCode() > 199 && r.StatusCode() < 300 +} + +func (r *Response) IsError() bool { + return r.StatusCode() > 399 +} From 7f12c8e50e2c3f3ec42f36e0b5b39b3415eee697 Mon Sep 17 00:00:00 2001 From: violapioggia Date: Thu, 16 May 2024 23:01:50 +0800 Subject: [PATCH 06/15] feat: optimize api client --- client.go | 9 +------ request.go | 7 ++---- response.go | 72 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/client.go b/client.go index daea7f3..8bba060 100644 --- a/client.go +++ b/client.go @@ -18,13 +18,11 @@ package easy_http import ( "context" + "github.com/cloudwego/hertz/pkg/app/client" "github.com/cloudwego/hertz/pkg/protocol" "net/http" "net/url" "sync" - "time" - - "github.com/cloudwego/hertz/pkg/app/client" ) type Client struct { @@ -230,8 +228,6 @@ func (c *Client) execute(req *Request) (*Response, error) { req.RawRequest.SetHost(hostHeader) } - req.Time = time.Now() - resp := &protocol.Response{} err = c.client.Do(context.Background(), req.RawRequest, resp) @@ -241,12 +237,9 @@ func (c *Client) execute(req *Request) (*Response, error) { } if err != nil { - response.receiveAt = time.Now() return response, err } - response.receiveAt = time.Now() - // Apply Response middleware for _, f := range c.afterResponse { if err = f(c, response); err != nil { diff --git a/request.go b/request.go index 8fb91d5..f8fb174 100644 --- a/request.go +++ b/request.go @@ -18,12 +18,10 @@ package easy_http import ( "context" - "net/http" - "net/url" - "time" - "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/protocol" + "net/http" + "net/url" ) type Request struct { @@ -38,7 +36,6 @@ type Request struct { FileParams map[string]string BodyParams interface{} RawRequest *protocol.Request - Time time.Time Ctx context.Context RequestOptions []config.RequestOption Result interface{} diff --git a/response.go b/response.go index 820074b..5b502c3 100644 --- a/response.go +++ b/response.go @@ -17,33 +17,30 @@ package easy_http import ( + "bytes" "github.com/cloudwego/hertz/pkg/protocol" + "io" + "net/http" "strings" - "time" ) type Response struct { Request *Request // 上面的 Request 结构体 RawResponse *protocol.Response - - receiveAt time.Time - - bodyByte []byte - size int64 } func (r *Response) Body() []byte { if r.RawResponse == nil { return []byte{} } - return r.bodyByte + return r.RawResponse.Body() } func (r *Response) BodyString() string { if r.RawResponse == nil { return "" } - return strings.TrimSpace(string(r.bodyByte)) + return strings.TrimSpace(string(r.RawResponse.Body())) } func (r *Response) StatusCode() int { @@ -61,23 +58,48 @@ func (r *Response) Error() interface{} { return r.Request.Error } -// todo -//func (r *Response) Header() http.Header { -// if r.RawResponse == nil { -// return http.Header{} -// } -// return r.RawResponse.Header.GetHeaders() -//} -// -//func (r *Response) Cookies() []*http.Cookie { -// if r.RawResponse == nil { -// return make([]*http.Cookie, 0) -// } -// return r.RawResponse.Header.GetCookies() -//} -//func (r *Response) ToRawHTTPResponse() string { -// return r.RawResponse.String() -//} +func (r *Response) Header() http.Header { + if r.RawResponse == nil { + return http.Header{} + } + header := make(http.Header) + r.RawResponse.Header.VisitAll(func(key, value []byte) { + keyStr := string(key) + values := header[keyStr] + values = append(values, string(value)) + header[keyStr] = values + }) + return header +} + +func (r *Response) Cookies() []*http.Cookie { + if r.RawResponse == nil { + return make([]*http.Cookie, 0) + } + var cookies []*http.Cookie + r.RawResponse.Header.VisitAllCookie(func(key, value []byte) { + cookies = append(cookies, &http.Cookie{ + Name: string(key), + Value: string(value), + }) + }) + + return cookies +} +func (r *Response) ToRawHTTPResponse() string { + resp := &http.Response{ + StatusCode: r.StatusCode(), + Header: r.Header(), + Body: io.NopCloser(bytes.NewReader(r.Body())), + } + for _, cookie := range r.Cookies() { + resp.Header.Add("Set-Cookie", cookie.String()) + } + var buffer bytes.Buffer + resp.Write(&buffer) + + return buffer.String() +} func (r *Response) IsSuccess() bool { return r.StatusCode() > 199 && r.StatusCode() < 300 From 4fa2fcee2c46df38cb1bff46a058017ad48e2d21 Mon Sep 17 00:00:00 2001 From: lance547 <437653103@qq.com> Date: Fri, 17 May 2024 14:39:00 +0800 Subject: [PATCH 07/15] feat:improve request --- request.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/request.go b/request.go index f8fb174..4469b3a 100644 --- a/request.go +++ b/request.go @@ -41,3 +41,70 @@ type Request struct { Result interface{} Error interface{} } + +const ( + // MethodGet HTTP method + MethodGet = "GET" + + // MethodPost HTTP method + MethodPost = "POST" + + // MethodPut HTTP method + MethodPut = "PUT" + + // MethodDelete HTTP method + MethodDelete = "DELETE" + + // MethodPatch HTTP method + MethodPatch = "PATCH" + + // MethodHead HTTP method + MethodHead = "HEAD" + + // MethodOptions HTTP method + MethodOptions = "OPTIONS" +) + + +func (r *Request) Get(url string) (*Response, error) { + return r.Execute(MethodGet, url) +} + +func (r *Request) Head(url string) (*Response, error) { + return r.Execute(MethodHead, url) +} + +func (r *Request) Post(url string) (*Response, error) { + return r.Execute(MethodPost, url) +} + +func (r *Request) Put(url string) (*Response, error) { + return r.Execute(MethodPut, url) +} + +func (r *Request) Delete(url string) (*Response, error) { + return r.Execute(MethodDelete, url) +} + +func (r *Request) Options(url string) (*Response, error) { + return r.Execute(MethodOptions, url) +} + +func (r *Request) Patch(url string) (*Response, error) { + return r.Execute(MethodPatch, url) +} + +func (r *Request) Send() (*Response, error) { + return r.Execute(r.Method, r.Url) +} + +func (r *Request) Execute(method, url string) (*Response, error) { + r.Method = method + r.Url = url + res := &Response{ + Request: r, + RawResponse: &protocol.Response{}, + } + err :=r.client.client.Do(context.Background(),r.RawRequest,res.RawResponse) + return res,err +} \ No newline at end of file From 535fbc4ff7cbed9e89a0871f83d0841c4bc6906c Mon Sep 17 00:00:00 2001 From: violapioggia Date: Tue, 21 May 2024 00:36:59 +0800 Subject: [PATCH 08/15] feat: optimize middleware --- client.go | 50 +++++++++++++++++-- easy_http.go | 4 +- example/main.go | 16 +++++++ middleware.go | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ request.go | 22 +++++---- 5 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 example/main.go diff --git a/client.go b/client.go index 8bba060..083fcf6 100644 --- a/client.go +++ b/client.go @@ -22,11 +22,13 @@ import ( "github.com/cloudwego/hertz/pkg/protocol" "net/http" "net/url" + "regexp" "sync" ) type Client struct { QueryParam url.Values + FormData map[string]string PathParams map[string]string Header http.Header Cookies []*http.Cookie @@ -45,8 +47,49 @@ type ( ResponseMiddleware func(*Client, *Response) error ) -func createClient(c *client.Client) *Client { - return &Client{client: c} +var ( + hdrUserAgentKey = http.CanonicalHeaderKey("User-Agent") + hdrAcceptKey = http.CanonicalHeaderKey("Accept") + hdrContentTypeKey = http.CanonicalHeaderKey("Content-Type") + hdrContentLengthKey = http.CanonicalHeaderKey("Content-Length") + hdrContentEncodingKey = http.CanonicalHeaderKey("Content-Encoding") + hdrLocationKey = http.CanonicalHeaderKey("Location") + hdrAuthorizationKey = http.CanonicalHeaderKey("Authorization") + hdrWwwAuthenticateKey = http.CanonicalHeaderKey("WWW-Authenticate") + + plainTextType = "text/plain; charset=utf-8" + jsonContentType = "application/json" + formContentType = "application/x-www-form-urlencoded" + formDataContentType = "multipart/form-data" + + jsonCheck = regexp.MustCompile(`(?i:(application|text)/(.*json.*)(;|$))`) + xmlCheck = regexp.MustCompile(`(?i:(application|text)/(.*xml.*)(;|$))`) +) + +func createClient(cc *client.Client) *Client { + c := &Client{ + QueryParam: url.Values{}, + PathParams: make(map[string]string), + Header: http.Header{}, + Cookies: make([]*http.Cookie, 0), + + udBeforeRequestLock: &sync.RWMutex{}, + afterResponseLock: &sync.RWMutex{}, + + client: cc, + } + + c.beforeRequest = []RequestMiddleware{ + parseRequestURL, + parseRequestHeader, + parseRequestBody, + } + + c.udBeforeRequest = []RequestMiddleware{} + + c.afterResponse = []ResponseMiddleware{} + + return c } func (c *Client) SetQueryParam(param, value string) *Client { @@ -114,7 +157,7 @@ func (c *Client) SetHeaders(headers map[string]string) *Client { func (c *Client) SetHeaderMultiValues(headers map[string][]string) *Client { for k, header := range headers { for _, v := range header { - c.Header.Set(k, v) + c.Header.Add(k, v) } } return c @@ -188,6 +231,7 @@ func (c *Client) R() *Request { Header: http.Header{}, Cookies: make([]*http.Cookie, 0), PathParams: map[string]string{}, + RawRequest: &protocol.Request{}, client: c, } diff --git a/easy_http.go b/easy_http.go index ff1fc86..5578a0d 100644 --- a/easy_http.go +++ b/easy_http.go @@ -20,7 +20,7 @@ import "github.com/cloudwego/hertz/pkg/app/client" func New() (*Client, error) { c, err := client.NewClient() - return &Client{client: c}, err + return createClient(c), err } func MustNew() *Client { @@ -28,7 +28,7 @@ func MustNew() *Client { if err != nil { panic(err) } - return &Client{client: c} + return createClient(c) } func NewWithHertzClient(c *client.Client) *Client { diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..4243c97 --- /dev/null +++ b/example/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "github.com/hertz-contrib/easy_http" +) + +func main() { + c := easy_http.MustNew() + + res, err := c.SetHeader("test", "test").SetQueryParam("test1", "test1").R().Get("http://www.baidu.com") + if err != nil { + panic(err) + } + fmt.Println(res) +} diff --git a/middleware.go b/middleware.go index 3a3909d..36e03ce 100644 --- a/middleware.go +++ b/middleware.go @@ -15,3 +15,127 @@ */ package easy_http + +import ( + "net/http" + "net/url" + "reflect" + "strings" +) + +func parseRequestURL(c *Client, r *Request) error { + if l := len(c.PathParams) + len(r.PathParams); l > 0 { + params := make(map[string]string, l) + + // GitHub #103 Path Params + for p, v := range r.PathParams { + params[p] = url.PathEscape(v) + } + for p, v := range c.PathParams { + if _, ok := params[p]; !ok { + params[p] = url.PathEscape(v) + } + } + + if len(params) > 0 { + + } + + for k, v := range params { + r.URL = strings.Replace(r.URL, "{"+k+"}", v, 1) + } + } + + // Parsing request URL + reqURL, err := url.Parse(r.URL) + if err != nil { + return err + } + + // Adding Query Param + if len(c.QueryParam)+len(r.QueryParam) > 0 { + for k, v := range c.QueryParam { + // skip query parameter if it was set in request + if _, ok := r.QueryParam[k]; ok { + continue + } + + r.QueryParam[k] = v[:] + } + + if len(r.QueryParam) > 0 { + if len(strings.TrimSpace(reqURL.RawQuery)) == 0 { + reqURL.RawQuery = r.QueryParam.Encode() + } else { + reqURL.RawQuery = reqURL.RawQuery + "&" + r.QueryParam.Encode() + } + } + } + + r.URL = reqURL.String() + + return nil +} + +func parseRequestHeader(c *Client, r *Request) error { + for k, v := range c.Header { + if _, ok := r.Header[k]; ok { + continue + } + r.Header[k] = v[:] + } + + return nil +} + +func parseRequestBody(c *Client, r *Request) error { + switch { + case r.RawRequest.HasMultipartForm(): // Handling Multipart + handleMultipart(c, r) + case len(c.FormData) > 0 || len(r.FormData) > 0: // Handling Form Data + handleFormData(c, r) + //case r.RawRequest.Body() != nil: // Handling Request body + // handleContentType(c, r) + } + + return nil +} + +func handleMultipart(c *Client, r *Request) { + r.RawRequest.SetMultipartFormData(c.FormData) + + r.Header.Set(hdrContentTypeKey, formDataContentType) +} + +func handleFormData(c *Client, r *Request) { + r.RawRequest.SetFormData(c.FormData) + + r.Header.Set(hdrContentTypeKey, formContentType) +} + +//func handleContentType(c *Client, r *Request) { +// contentType := r.Header.Get(hdrContentTypeKey) +// if len(strings.TrimSpace(contentType)) == 0 { +// contentType = DetectContentType(r.RawRequest.Body()) +// r.Header.Set(hdrContentTypeKey, contentType) +// } +//} + +func DetectContentType(body interface{}) string { + contentType := plainTextType + kind := reflect.Indirect(reflect.ValueOf(body)).Kind() + switch kind { + case reflect.Struct, reflect.Map: + contentType = jsonContentType + case reflect.String: + contentType = plainTextType + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = jsonContentType + } + } + + return contentType +} diff --git a/request.go b/request.go index 4469b3a..df8a392 100644 --- a/request.go +++ b/request.go @@ -26,14 +26,14 @@ import ( type Request struct { client *Client - Url string + URL string Method string QueryParam url.Values Header http.Header Cookies []*http.Cookie PathParams map[string]string - FormParams map[string]string - FileParams map[string]string + FormData map[string]string + FileData map[string]string BodyParams interface{} RawRequest *protocol.Request Ctx context.Context @@ -65,7 +65,6 @@ const ( MethodOptions = "OPTIONS" ) - func (r *Request) Get(url string) (*Response, error) { return r.Execute(MethodGet, url) } @@ -95,16 +94,19 @@ func (r *Request) Patch(url string) (*Response, error) { } func (r *Request) Send() (*Response, error) { - return r.Execute(r.Method, r.Url) + return r.Execute(r.Method, r.URL) } func (r *Request) Execute(method, url string) (*Response, error) { r.Method = method - r.Url = url + + r.RawRequest.SetRequestURI(url) res := &Response{ - Request: r, + Request: r, RawResponse: &protocol.Response{}, } - err :=r.client.client.Do(context.Background(),r.RawRequest,res.RawResponse) - return res,err -} \ No newline at end of file + + var err error + res, err = r.client.execute(r) + return res, err +} From 9f0b5abaa510bdf678287989b43f4b119d6d0714 Mon Sep 17 00:00:00 2001 From: lance547 <437653103@qq.com> Date: Wed, 22 May 2024 21:51:32 +0800 Subject: [PATCH 09/15] feat:add some api --- request.go | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 3 deletions(-) diff --git a/request.go b/request.go index df8a392..87f7b89 100644 --- a/request.go +++ b/request.go @@ -18,10 +18,15 @@ package easy_http import ( "context" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/protocol" + "fmt" + "io" "net/http" "net/url" + "reflect" + "strings" + + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/protocol" ) type Request struct { @@ -29,10 +34,10 @@ type Request struct { URL string Method string QueryParam url.Values + FormData url.Values Header http.Header Cookies []*http.Cookie PathParams map[string]string - FormData map[string]string FileData map[string]string BodyParams interface{} RawRequest *protocol.Request @@ -40,6 +45,8 @@ type Request struct { RequestOptions []config.RequestOption Result interface{} Error interface{} + isMultiPart bool + multipartFiles []*File } const ( @@ -64,7 +71,176 @@ const ( // MethodOptions HTTP method MethodOptions = "OPTIONS" ) +type File struct { + Name string + ParamName string + io.Reader +} +func (r *Request) SetQueryParam(param, value string) *Request { + r.QueryParam.Set(param, value) + return r +} +func (r *Request) SetQueryParams(params map[string]string) *Request { + for p, v := range params { + r.SetQueryParam(p, v) + } + return r +} +func (r *Request) SetQueryParamsFromValues(params url.Values) *Request { + for p, v := range params { + for _, pv := range v { + r.QueryParam.Add(p, pv) + } + } + return r +} +func (r *Request) SetQueryString(query string) *Request { + params, err := url.ParseQuery(strings.TrimSpace(query)) + if err == nil { + for p, v := range params { + for _, pv := range v { + r.QueryParam.Add(p, pv) + } + } + } else { + fmt.Printf("%v",err) + } + return r +} +func (r * Request) AddQueryParam(params,value string)*Request{ + r.QueryParam.Add(params,value) + return r +} +func (r *Request) AddQueryParams(params map[string]string)*Request{ + for k,v :=range params{ + r.AddQueryParam(k,v) + } + return r +} +func (r *Request) SetPathParam(param, value string) *Request { + r.PathParams[param] = value + return r +} +func (r *Request) SetPathParams(params map[string]string) *Request { + for p, v := range params { + r.SetPathParam(p, v) + } + return r +} + +func (r *Request) SetHeader(header, value string) *Request { + r.Header.Set(header, value) + return r +} + +func (r *Request) SetHeaders(headers map[string]string) *Request { + for h, v := range headers { + r.SetHeader(h, v) + } + return r +} +func (r *Request) SetHeaderMultiValues(headers map[string][]string) *Request { + for key, values := range headers { + r.SetHeader(key, strings.Join(values, ", ")) + } + return r +} +func (r * Request) AddHeader(header , value string)*Request{ + r.Header.Add(header,value) + return r +} +func (r *Request) AddHeaders(headers map[string]string)*Request{ + for k , v :=range headers{ + r.AddHeader(k,v) + } + return r +} +func (r *Request)AddHeaderMultiValues(headers map[string][]string)*Request{ + for key ,value := range headers{ + r.AddHeader(key,strings.Join(value,", ")) + } + return r +} +// [] SetContentType(contentType string) +// [] SetJSONContentType() (可添加一些常用的 content-type) +func (r *Request) SetCookie(hc *http.Cookie) *Request { + r.Cookies = append(r.Cookies, hc) + return r +} +func (r *Request) SetCookies(rs []*http.Cookie) *Request { + r.Cookies = append(r.Cookies, rs...) + return r +} +// [] SetJSONBody(body interface{}) (自动注入 json content-type,参数可以是 strcut、map、[]byte、string 等) +// [] SetUrlEncodeBody(body url.Value) (自动注入 urlencode content-type) +func (r *Request) SetBody(body interface{}) *Request { + r.BodyParams= body + return r +} +func (r *Request) SetFormData(data map[string]string) *Request { + for k ,v :=range data{ + r.FormData.Set(k,v) + } + return r +} +func (r *Request) SetFormDataFromValues(data url.Values) *Request { + for key ,value := range data{ + for _,v :=range value{ + r.FormData.Add(key,v) + } + } + return r +} +func (r *Request) SetFiles(files map[string]string) *Request { + r.isMultiPart = true + for f, fp := range files { + r.FormData.Set("@"+f, fp) + } + return r +} + +func (r *Request) SetFileReader(param, fileName string, reader io.Reader) *Request { + r.isMultiPart = true + r.multipartFiles = append(r.multipartFiles, &File{ + Name: fileName, + ParamName: param, + Reader: reader, + }) + return r +} +func (r *Request) SetResult(res interface{}) *Request { + if res != nil { + vv := reflect.ValueOf(res) + if vv.Kind() == reflect.Ptr{ + r.Result = res + }else { + r.Result = reflect.New(vv.Type()).Interface() + } + } + return r +} +// [] WithContext(ctx) +// [] WithDC(dc) +// [] WithCluster(cluster) +// [] WithEnv(env) +// [] WIthCallTimeout(t) +func (r * Request)WithContext(ctx context.Context)*Request{ + r.Ctx = ctx + return r +} +func (r * Request)WithDC()*Request{ + return r +} +func (r * Request)WithCluster()*Request{ + return r +} +func (r * Request)WithEnv()*Request{ + return r +} +func (r * Request)WIthCallTimeout()*Request{ + return r +} func (r *Request) Get(url string) (*Response, error) { return r.Execute(MethodGet, url) } @@ -110,3 +286,4 @@ func (r *Request) Execute(method, url string) (*Response, error) { res, err = r.client.execute(r) return res, err } + From ac162ef85d25718477a038e9043b1860609a176d Mon Sep 17 00:00:00 2001 From: violapioggia Date: Thu, 23 May 2024 00:52:42 +0800 Subject: [PATCH 10/15] feat: initialize client_test.go --- client.go | 11 +++++-- client_test.go | 20 +++++++++++++ easy_http_test.go | 1 + go.mod | 8 ++++- go.sum | 1 + request.go | 75 +++++++++++++++++++++++++---------------------- 6 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 client_test.go create mode 100644 easy_http_test.go diff --git a/client.go b/client.go index 083fcf6..4df22e3 100644 --- a/client.go +++ b/client.go @@ -23,6 +23,7 @@ import ( "net/http" "net/url" "regexp" + "strings" "sync" ) @@ -114,7 +115,14 @@ func (c *Client) SetQueryParamsFromValues(params url.Values) *Client { } func (c *Client) SetQueryString(query string) *Client { - // todo: parse query string + str := strings.Split(query, "&") + for _, v := range str { + kv := strings.Split(v, "=") + if len(kv) == 2 { + c.QueryParam.Set(kv[0], kv[1]) + } + + } return c } @@ -229,7 +237,6 @@ func (c *Client) R() *Request { r := &Request{ QueryParam: url.Values{}, Header: http.Header{}, - Cookies: make([]*http.Cookie, 0), PathParams: map[string]string{}, RawRequest: &protocol.Request{}, diff --git a/client_test.go b/client_test.go new file mode 100644 index 0000000..a426081 --- /dev/null +++ b/client_test.go @@ -0,0 +1,20 @@ +package easy_http + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSetQueryParam(t *testing.T) { + c := MustNew() + c.SetQueryParam("test1", "test1") + c.SetQueryParams(map[string]string{"test2": "test2", "test3": "test3"}) + c.SetQueryParamsFromValues(map[string][]string{"test4": {"test41", "test42"}}) + c.SetQueryString("test5=test5") + + assert.Equal(t, "test1", c.QueryParam.Get("test1")) + assert.Equal(t, "test2", c.QueryParam.Get("test2")) + assert.Equal(t, "test3", c.QueryParam.Get("test3")) + assert.Equal(t, []string{"test41", "test42"}, c.QueryParam["test4"]) + assert.Equal(t, "test5", c.QueryParam.Get("test5")) +} diff --git a/easy_http_test.go b/easy_http_test.go new file mode 100644 index 0000000..a848917 --- /dev/null +++ b/easy_http_test.go @@ -0,0 +1 @@ +package easy_http diff --git a/go.mod b/go.mod index 63ffc84..db468bf 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module github.com/hertz-contrib/easy_http go 1.19 -require github.com/cloudwego/hertz v0.8.1 +require ( + github.com/cloudwego/hertz v0.8.1 + github.com/stretchr/testify v1.8.1 +) require ( github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect @@ -10,12 +13,14 @@ require ( github.com/bytedance/sonic v1.8.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cloudwego/netpoll v0.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/golang/protobuf v1.5.0 // indirect github.com/henrylee2cn/ameda v1.4.10 // indirect github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect @@ -23,4 +28,5 @@ require ( golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 36f7131..4543376 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/request.go b/request.go index 87f7b89..3f30791 100644 --- a/request.go +++ b/request.go @@ -36,7 +36,6 @@ type Request struct { QueryParam url.Values FormData url.Values Header http.Header - Cookies []*http.Cookie PathParams map[string]string FileData map[string]string BodyParams interface{} @@ -45,8 +44,8 @@ type Request struct { RequestOptions []config.RequestOption Result interface{} Error interface{} - isMultiPart bool - multipartFiles []*File + isMultiPart bool + multipartFiles []*File } const ( @@ -71,11 +70,13 @@ const ( // MethodOptions HTTP method MethodOptions = "OPTIONS" ) + type File struct { Name string ParamName string io.Reader } + func (r *Request) SetQueryParam(param, value string) *Request { r.QueryParam.Set(param, value) return r @@ -103,17 +104,17 @@ func (r *Request) SetQueryString(query string) *Request { } } } else { - fmt.Printf("%v",err) + fmt.Printf("%v", err) } return r } -func (r * Request) AddQueryParam(params,value string)*Request{ - r.QueryParam.Add(params,value) +func (r *Request) AddQueryParam(params, value string) *Request { + r.QueryParam.Add(params, value) return r } -func (r *Request) AddQueryParams(params map[string]string)*Request{ - for k,v :=range params{ - r.AddQueryParam(k,v) +func (r *Request) AddQueryParams(params map[string]string) *Request { + for k, v := range params { + r.AddQueryParam(k, v) } return r } @@ -146,50 +147,54 @@ func (r *Request) SetHeaderMultiValues(headers map[string][]string) *Request { } return r } -func (r * Request) AddHeader(header , value string)*Request{ - r.Header.Add(header,value) +func (r *Request) AddHeader(header, value string) *Request { + r.Header.Add(header, value) return r } -func (r *Request) AddHeaders(headers map[string]string)*Request{ - for k , v :=range headers{ - r.AddHeader(k,v) +func (r *Request) AddHeaders(headers map[string]string) *Request { + for k, v := range headers { + r.AddHeader(k, v) } return r } -func (r *Request)AddHeaderMultiValues(headers map[string][]string)*Request{ - for key ,value := range headers{ - r.AddHeader(key,strings.Join(value,", ")) - } +func (r *Request) AddHeaderMultiValues(headers map[string][]string) *Request { + for key, value := range headers { + r.AddHeader(key, strings.Join(value, ", ")) + } return r } + // [] SetContentType(contentType string) // [] SetJSONContentType() (可添加一些常用的 content-type) func (r *Request) SetCookie(hc *http.Cookie) *Request { - r.Cookies = append(r.Cookies, hc) + r.RawRequest.SetCookie(hc.Name, hc.Value) return r } func (r *Request) SetCookies(rs []*http.Cookie) *Request { - r.Cookies = append(r.Cookies, rs...) + for _, c := range rs { + r.RawRequest.SetCookie(c.Name, c.Value) + } return r } + // [] SetJSONBody(body interface{}) (自动注入 json content-type,参数可以是 strcut、map、[]byte、string 等) // [] SetUrlEncodeBody(body url.Value) (自动注入 urlencode content-type) func (r *Request) SetBody(body interface{}) *Request { - r.BodyParams= body + r.BodyParams = body return r } func (r *Request) SetFormData(data map[string]string) *Request { - for k ,v :=range data{ - r.FormData.Set(k,v) + for k, v := range data { + r.FormData.Set(k, v) } return r } func (r *Request) SetFormDataFromValues(data url.Values) *Request { - for key ,value := range data{ - for _,v :=range value{ - r.FormData.Add(key,v) + for key, value := range data { + for _, v := range value { + r.FormData.Add(key, v) } - } + } return r } func (r *Request) SetFiles(files map[string]string) *Request { @@ -212,33 +217,34 @@ func (r *Request) SetFileReader(param, fileName string, reader io.Reader) *Reque func (r *Request) SetResult(res interface{}) *Request { if res != nil { vv := reflect.ValueOf(res) - if vv.Kind() == reflect.Ptr{ + if vv.Kind() == reflect.Ptr { r.Result = res - }else { + } else { r.Result = reflect.New(vv.Type()).Interface() } } return r } + // [] WithContext(ctx) // [] WithDC(dc) // [] WithCluster(cluster) // [] WithEnv(env) // [] WIthCallTimeout(t) -func (r * Request)WithContext(ctx context.Context)*Request{ +func (r *Request) WithContext(ctx context.Context) *Request { r.Ctx = ctx return r } -func (r * Request)WithDC()*Request{ +func (r *Request) WithDC() *Request { return r } -func (r * Request)WithCluster()*Request{ +func (r *Request) WithCluster() *Request { return r } -func (r * Request)WithEnv()*Request{ +func (r *Request) WithEnv() *Request { return r } -func (r * Request)WIthCallTimeout()*Request{ +func (r *Request) WIthCallTimeout() *Request { return r } func (r *Request) Get(url string) (*Response, error) { @@ -286,4 +292,3 @@ func (r *Request) Execute(method, url string) (*Response, error) { res, err = r.client.execute(r) return res, err } - From 52406c3659c3bd5af378212bd02cb16d49b9dbbb Mon Sep 17 00:00:00 2001 From: violapioggia Date: Mon, 27 May 2024 00:39:54 +0800 Subject: [PATCH 11/15] style: adjust config --- client.go | 15 ++------------- request.go | 12 ++---------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/client.go b/client.go index 4df22e3..499570d 100644 --- a/client.go +++ b/client.go @@ -22,7 +22,6 @@ import ( "github.com/cloudwego/hertz/pkg/protocol" "net/http" "net/url" - "regexp" "strings" "sync" ) @@ -49,22 +48,12 @@ type ( ) var ( - hdrUserAgentKey = http.CanonicalHeaderKey("User-Agent") - hdrAcceptKey = http.CanonicalHeaderKey("Accept") - hdrContentTypeKey = http.CanonicalHeaderKey("Content-Type") - hdrContentLengthKey = http.CanonicalHeaderKey("Content-Length") - hdrContentEncodingKey = http.CanonicalHeaderKey("Content-Encoding") - hdrLocationKey = http.CanonicalHeaderKey("Location") - hdrAuthorizationKey = http.CanonicalHeaderKey("Authorization") - hdrWwwAuthenticateKey = http.CanonicalHeaderKey("WWW-Authenticate") + hdrContentTypeKey = http.CanonicalHeaderKey("Content-Type") plainTextType = "text/plain; charset=utf-8" jsonContentType = "application/json" formContentType = "application/x-www-form-urlencoded" formDataContentType = "multipart/form-data" - - jsonCheck = regexp.MustCompile(`(?i:(application|text)/(.*json.*)(;|$))`) - xmlCheck = regexp.MustCompile(`(?i:(application|text)/(.*xml.*)(;|$))`) ) func createClient(cc *client.Client) *Client { @@ -218,7 +207,7 @@ func (c *Client) SetFormContentType() *Client { } -func (c *Client) SetXFormData() *Client { +func (c *Client) SetFormData() *Client { c.Header.Set("Content-Type", "multipart/form-data") return c } diff --git a/request.go b/request.go index 3f30791..286b1fe 100644 --- a/request.go +++ b/request.go @@ -164,8 +164,6 @@ func (r *Request) AddHeaderMultiValues(headers map[string][]string) *Request { return r } -// [] SetContentType(contentType string) -// [] SetJSONContentType() (可添加一些常用的 content-type) func (r *Request) SetCookie(hc *http.Cookie) *Request { r.RawRequest.SetCookie(hc.Name, hc.Value) return r @@ -177,8 +175,6 @@ func (r *Request) SetCookies(rs []*http.Cookie) *Request { return r } -// [] SetJSONBody(body interface{}) (自动注入 json content-type,参数可以是 strcut、map、[]byte、string 等) -// [] SetUrlEncodeBody(body url.Value) (自动注入 urlencode content-type) func (r *Request) SetBody(body interface{}) *Request { r.BodyParams = body return r @@ -226,16 +222,12 @@ func (r *Request) SetResult(res interface{}) *Request { return r } -// [] WithContext(ctx) -// [] WithDC(dc) -// [] WithCluster(cluster) -// [] WithEnv(env) -// [] WIthCallTimeout(t) func (r *Request) WithContext(ctx context.Context) *Request { r.Ctx = ctx return r } -func (r *Request) WithDC() *Request { +func (r *Request) WithDC(ctx context.Context) *Request { + return r } func (r *Request) WithCluster() *Request { From da9bb183dcbd4486b499bc323558cdfb86a162a4 Mon Sep 17 00:00:00 2001 From: violapioggia Date: Wed, 29 May 2024 18:17:13 +0800 Subject: [PATCH 12/15] feat: optimize options --- request.go | 83 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/request.go b/request.go index 286b1fe..d167cc6 100644 --- a/request.go +++ b/request.go @@ -18,12 +18,14 @@ package easy_http import ( "context" - "fmt" + "github.com/cloudwego/hertz/pkg/app/client/discovery" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" "io" "net/http" "net/url" "reflect" "strings" + "time" "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/protocol" @@ -37,8 +39,6 @@ type Request struct { FormData url.Values Header http.Header PathParams map[string]string - FileData map[string]string - BodyParams interface{} RawRequest *protocol.Request Ctx context.Context RequestOptions []config.RequestOption @@ -96,16 +96,7 @@ func (r *Request) SetQueryParamsFromValues(params url.Values) *Request { return r } func (r *Request) SetQueryString(query string) *Request { - params, err := url.ParseQuery(strings.TrimSpace(query)) - if err == nil { - for p, v := range params { - for _, pv := range v { - r.QueryParam.Add(p, pv) - } - } - } else { - fmt.Printf("%v", err) - } + r.RawRequest.SetQueryString(query) return r } func (r *Request) AddQueryParam(params, value string) *Request { @@ -176,7 +167,19 @@ func (r *Request) SetCookies(rs []*http.Cookie) *Request { } func (r *Request) SetBody(body interface{}) *Request { - r.BodyParams = body + t := reflect.Indirect(reflect.ValueOf(body)).Type().Kind() + + switch t { + case reflect.String: + r.RawRequest.SetBodyString(body.(string)) + case reflect.TypeOf([]byte{}).Kind(): + r.RawRequest.SetBody(body.([]byte)) + case reflect.TypeOf(io.Reader(nil)).Kind(): + r.RawRequest.SetBodyStream(body.(io.Reader), -1) + default: + panic("unsupported body type") + } + return r } func (r *Request) SetFormData(data map[string]string) *Request { @@ -226,8 +229,55 @@ func (r *Request) WithContext(ctx context.Context) *Request { r.Ctx = ctx return r } -func (r *Request) WithDC(ctx context.Context) *Request { +const ( + defaultNetwork = "tcp" +) + +type customizedResolver struct { + Address string +} + +var _ discovery.Resolver = (*customizedResolver)(nil) + +// NewResolver create a service resolver. +func NewResolver(address string) discovery.Resolver { + return &customizedResolver{ + Address: address, + } +} + +// Target return a description for the given target that is suitable for being a key for cache. +func (c *customizedResolver) Target(_ context.Context, target *discovery.TargetInfo) (description string) { + return target.Host +} + +// Name returns the name of the resolver. +func (c *customizedResolver) Name() string { + return "easy_http" +} + +// Resolve a service info by desc. +func (c *customizedResolver) Resolve(_ context.Context, desc string) (discovery.Result, error) { + var eps []discovery.Instance + + tags := map[string]string{} + eps = append(eps, discovery.NewInstance( + defaultNetwork, + c.Address, + 1, + tags, + )) + + return discovery.Result{ + CacheKey: desc, + Instances: eps, + }, nil +} + +func (r *Request) WithDC(dc string) *Request { + resolver := NewResolver(dc) + r.client.client.Use(sd.Discovery(resolver)) return r } func (r *Request) WithCluster() *Request { @@ -236,7 +286,8 @@ func (r *Request) WithCluster() *Request { func (r *Request) WithEnv() *Request { return r } -func (r *Request) WIthCallTimeout() *Request { +func (r *Request) WIthCallTimeout(t time.Duration) *Request { + r.RawRequest.SetOptions(config.WithDialTimeout(t)) return r } func (r *Request) Get(url string) (*Response, error) { From ec738a739af529b6e46d3c902dc20cb2bf61638b Mon Sep 17 00:00:00 2001 From: violapioggia Date: Wed, 29 May 2024 18:21:02 +0800 Subject: [PATCH 13/15] chore: adjust fileReader --- request.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/request.go b/request.go index d167cc6..f17c9bc 100644 --- a/request.go +++ b/request.go @@ -45,7 +45,6 @@ type Request struct { Result interface{} Error interface{} isMultiPart bool - multipartFiles []*File } const ( @@ -205,12 +204,7 @@ func (r *Request) SetFiles(files map[string]string) *Request { } func (r *Request) SetFileReader(param, fileName string, reader io.Reader) *Request { - r.isMultiPart = true - r.multipartFiles = append(r.multipartFiles, &File{ - Name: fileName, - ParamName: param, - Reader: reader, - }) + r.RawRequest.SetFileReader(param, fileName, reader) return r } func (r *Request) SetResult(res interface{}) *Request { From 7ce34d5987e2924d828459ff53b825211c9b5e52 Mon Sep 17 00:00:00 2001 From: violapioggia Date: Wed, 29 May 2024 18:27:13 +0800 Subject: [PATCH 14/15] go mod tidy --- go.mod | 1 + go.sum | 1 + 2 files changed, 2 insertions(+) diff --git a/go.mod b/go.mod index db468bf..5605cb7 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 4543376..6370c81 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,7 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VA golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From ae38876e0ed0d09567c72d485f3eb33a5c400c7f Mon Sep 17 00:00:00 2001 From: violapioggia Date: Fri, 7 Jun 2024 22:34:02 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20client=20=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client_test.go | 2 +- easy_http.go | 145 +++++++++++++++++++++++++++++++++++++++++++++--- example/main.go | 23 +++++++- 3 files changed, 158 insertions(+), 12 deletions(-) diff --git a/client_test.go b/client_test.go index a426081..744cc68 100644 --- a/client_test.go +++ b/client_test.go @@ -6,7 +6,7 @@ import ( ) func TestSetQueryParam(t *testing.T) { - c := MustNew() + c := MustNewClient(&Option{}) c.SetQueryParam("test1", "test1") c.SetQueryParams(map[string]string{"test2": "test2", "test3": "test3"}) c.SetQueryParamsFromValues(map[string][]string{"test4": {"test41", "test42"}}) diff --git a/easy_http.go b/easy_http.go index 5578a0d..e5dd8ed 100644 --- a/easy_http.go +++ b/easy_http.go @@ -16,21 +16,148 @@ package easy_http -import "github.com/cloudwego/hertz/pkg/app/client" +import ( + "crypto/tls" + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/client/retry" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/network" + "time" +) -func New() (*Client, error) { - c, err := client.NewClient() +type Option struct { + c *client.Client + F []config.ClientOption +} + +func NewOption() *Option { + return &Option{} +} + +func (o *Option) WithHertzRawOption(c *client.Client) *Option { + o.c = c + return o +} + +func (o *Option) WithDialTimeout(dialTimeout time.Duration) *Option { + o.F = append(o.F, client.WithDialTimeout(dialTimeout)) + return o +} + +func (o *Option) WithMaxConnsPerHost(mc int) *Option { + o.F = append(o.F, client.WithMaxConnsPerHost(mc)) + return o +} + +func (o *Option) WithMaxIdleConnDuration(t time.Duration) *Option { + o.F = append(o.F, client.WithMaxIdleConnDuration(t)) + return o +} + +func (o *Option) WithMaxConnDuration(t time.Duration) *Option { + o.F = append(o.F, client.WithMaxConnDuration(t)) + return o +} + +func (o *Option) WithMaxConnWaitTimeout(t time.Duration) *Option { + o.F = append(o.F, client.WithMaxConnWaitTimeout(t)) + return o +} + +func (o *Option) WithKeepAlive(keepAlive bool) *Option { + o.F = append(o.F, client.WithKeepAlive(keepAlive)) + return o +} + +func (o *Option) WithTLSConfig(tlsConfig *tls.Config) *Option { + o.F = append(o.F, client.WithTLSConfig(tlsConfig)) + return o +} + +func (o *Option) WithDialer(dialer network.Dialer) *Option { + o.F = append(o.F, client.WithDialer(dialer)) + return o +} + +func (o *Option) WithResponseBodyStream(flag bool) *Option { + o.F = append(o.F, client.WithResponseBodyStream(flag)) + return o +} + +func (o *Option) WithDisableHeaderNamesNormalizing(flag bool) *Option { + o.F = append(o.F, client.WithDisableHeaderNamesNormalizing(flag)) + return o +} + +func (o *Option) WithName(name string) *Option { + o.F = append(o.F, client.WithName(name)) + return o +} + +func (o *Option) WithNoDefaultUserAgentHeader(flag bool) *Option { + o.F = append(o.F, client.WithNoDefaultUserAgentHeader(flag)) + return o +} + +func (o *Option) WithDisablePathNormalizing(flag bool) *Option { + o.F = append(o.F, client.WithDisablePathNormalizing(flag)) + return o +} + +func (o *Option) WithRetryConfig(retryConfig retry.Option) *Option { + o.F = append(o.F, client.WithRetryConfig(retryConfig)) + return o +} + +func (o *Option) WithWriteTimeout(t time.Duration) *Option { + o.F = append(o.F, client.WithWriteTimeout(t)) + return o +} + +func (o *Option) WithConnStateObserve(hs config.HostClientStateFunc, interval ...time.Duration) *Option { + o.F = append(o.F, client.WithConnStateObserve(hs, interval...)) + return o +} + +func (o *Option) WithDialFunc(f network.DialFunc) *Option { + o.F = append(o.F, client.WithDialFunc(f)) + return o +} + +func (o *Option) WithHostClientConfigHook(h func(hc interface{}) error) *Option { + o.F = append(o.F, client.WithHostClientConfigHook(h)) + return o +} + +func NewClient(opts *Option) (*Client, error) { + var hertzOptions []config.ClientOption + + if opts.c != nil { + return createClient(opts.c), nil + } + + for _, f := range opts.F { + hertzOptions = append(hertzOptions, f) + } + + c, err := client.NewClient(hertzOptions...) return createClient(c), err } -func MustNew() *Client { - c, err := client.NewClient() +func MustNewClient(opts *Option) *Client { + var hertzOptions []config.ClientOption + + if opts.c != nil { + return createClient(opts.c) + } + + for _, f := range opts.F { + hertzOptions = append(hertzOptions, f) + } + + c, err := client.NewClient(hertzOptions...) if err != nil { panic(err) } return createClient(c) } - -func NewWithHertzClient(c *client.Client) *Client { - return createClient(c) -} diff --git a/example/main.go b/example/main.go index 4243c97..a8a58f4 100644 --- a/example/main.go +++ b/example/main.go @@ -2,15 +2,34 @@ package main import ( "fmt" + "github.com/cloudwego/hertz/pkg/app/client" "github.com/hertz-contrib/easy_http" ) func main() { - c := easy_http.MustNew() + opts1 := easy_http.NewOption().WithDialTimeout(10).WithWriteTimeout(10) + hertzClient, _ := client.NewClient(client.WithDialTimeout(10), client.WithWriteTimeout(10)) + opts2 := easy_http.NewOption().WithHertzRawOption(hertzClient) - res, err := c.SetHeader("test", "test").SetQueryParam("test1", "test1").R().Get("http://www.baidu.com") + c1, _ := easy_http.NewClient(opts1) + c2 := easy_http.MustNewClient(opts2) + c3 := easy_http.MustNewClient(&easy_http.Option{}) + + res, err := c1.SetHeader("test", "test").SetQueryParam("test1", "test1").R().Get("http://www.baidu.com") + if err != nil { + panic(err) + } + fmt.Println(res) + + res, err = c2.SetHeader("test", "test").SetQueryParam("test1", "test1").R().Get("http://www.baidu.com") if err != nil { panic(err) } + + res, err = c3.SetHeader("test", "test").SetQueryParam("test1", "test1").R().Get("http://www.baidu.com") + if err != nil { + panic(err) + } + fmt.Println(res) }