Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
8de7912a91 | |||
6ccb40bab0 | |||
2b16a8a7a6 | |||
|
d051256839 | ||
68b32989fc | |||
21a41a8e03 |
2
go.mod
2
go.mod
@@ -2,4 +2,4 @@ module github.com/unistack-org/micro-client-http/v3
|
|||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require github.com/unistack-org/micro/v3 v3.3.11
|
require github.com/unistack-org/micro/v3 v3.3.13
|
||||||
|
6
go.sum
6
go.sum
@@ -5,9 +5,9 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
||||||
github.com/unistack-org/micro/v3 v3.3.11 h1:Jr0gAw5lLqgddiHKQeWUOUeP6ZqgRhz52EA9zJ5MJ3U=
|
github.com/unistack-org/micro/v3 v3.3.13 h1:y4bDDkbwnjgOckrhFkC6D/o42tr75X33UbrB+Ko0M68=
|
||||||
github.com/unistack-org/micro/v3 v3.3.11/go.mod h1:PPCt675o3HPcODFbJ4iRWPmQFAk1WQ+asQSOb/syq6U=
|
github.com/unistack-org/micro/v3 v3.3.13/go.mod h1:98hNcMXp/WyWJwLwCuwrhN1Jm7aCWaRNsMfRjK8Fq+Y=
|
||||||
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
58
http.go
58
http.go
@@ -11,6 +11,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/broker"
|
"github.com/unistack-org/micro/v3/broker"
|
||||||
@@ -19,7 +21,6 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/errors"
|
"github.com/unistack-org/micro/v3/errors"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -36,6 +37,7 @@ type httpClient struct {
|
|||||||
dialer *net.Dialer
|
dialer *net.Dialer
|
||||||
httpcli *http.Client
|
httpcli *http.Client
|
||||||
init bool
|
init bool
|
||||||
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRequest(addr string, req client.Request, ct string, cf codec.Codec, msg interface{}, opts client.CallOptions) (*http.Request, error) {
|
func newRequest(addr string, req client.Request, ct string, cf codec.Codec, msg interface{}, opts client.CallOptions) (*http.Request, error) {
|
||||||
@@ -99,21 +101,9 @@ func newRequest(addr string, req client.Request, ct string, cf codec.Codec, msg
|
|||||||
return nil, errors.BadRequest("go.micro.client", err.Error())
|
return nil, errors.BadRequest("go.micro.client", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
var b []byte
|
b, err := cf.Marshal(nmsg)
|
||||||
|
if err != nil {
|
||||||
if nmsg != nil {
|
return nil, errors.BadRequest("go.micro.client", err.Error())
|
||||||
if ct == "application/x-www-form-urlencoded" {
|
|
||||||
data, err := rutil.StructURLValues(nmsg, "", tags)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.BadRequest("go.micro.client", err.Error())
|
|
||||||
}
|
|
||||||
b = []byte(data.Encode())
|
|
||||||
} else {
|
|
||||||
b, err = cf.Marshal(nmsg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.BadRequest("go.micro.client", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b) > 0 {
|
if len(b) > 0 {
|
||||||
@@ -133,26 +123,19 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ct := req.ContentType()
|
ct := req.ContentType()
|
||||||
|
if len(opts.ContentType) > 0 {
|
||||||
|
ct = opts.ContentType
|
||||||
|
}
|
||||||
|
|
||||||
// set timeout in nanoseconds
|
// set timeout in nanoseconds
|
||||||
header.Set("Timeout", fmt.Sprintf("%d", opts.RequestTimeout))
|
header.Set("Timeout", fmt.Sprintf("%d", opts.RequestTimeout))
|
||||||
// set the content type for the request
|
// set the content type for the request
|
||||||
header.Set("Content-Type", ct)
|
header.Set("Content-Type", ct)
|
||||||
|
|
||||||
var cf codec.Codec
|
cf, err := h.newCodec(ct)
|
||||||
var err error
|
|
||||||
// get codec
|
|
||||||
switch ct {
|
|
||||||
case "application/x-www-form-urlencoded":
|
|
||||||
cf, err = h.newCodec(DefaultContentType)
|
|
||||||
default:
|
|
||||||
cf, err = h.newCodec(ct)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InternalServerError("go.micro.client", err.Error())
|
return errors.InternalServerError("go.micro.client", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
hreq, err := newRequest(addr, req, ct, cf, req.Body(), opts)
|
hreq, err := newRequest(addr, req, ct, cf, req.Body(), opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -178,7 +161,13 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request,
|
|||||||
|
|
||||||
defer hrsp.Body.Close()
|
defer hrsp.Body.Close()
|
||||||
|
|
||||||
return parseRsp(ctx, hrsp, cf, rsp, opts)
|
if ct == "application/x-www-form-urlencoded" {
|
||||||
|
cf, err = h.newCodec(DefaultContentType)
|
||||||
|
if err != nil {
|
||||||
|
return errors.InternalServerError("go.micro.client", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h.parseRsp(ctx, hrsp, rsp, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpClient) stream(ctx context.Context, addr string, req client.Request, opts client.CallOptions) (client.Stream, error) {
|
func (h *httpClient) stream(ctx context.Context, addr string, req client.Request, opts client.CallOptions) (client.Stream, error) {
|
||||||
@@ -194,13 +183,17 @@ func (h *httpClient) stream(ctx context.Context, addr string, req client.Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
ct := req.ContentType()
|
ct := req.ContentType()
|
||||||
|
if len(opts.ContentType) > 0 {
|
||||||
|
ct = opts.ContentType
|
||||||
|
}
|
||||||
|
|
||||||
// set timeout in nanoseconds
|
// set timeout in nanoseconds
|
||||||
header.Set("Timeout", fmt.Sprintf("%d", opts.RequestTimeout))
|
header.Set("Timeout", fmt.Sprintf("%d", opts.RequestTimeout))
|
||||||
// set the content type for the request
|
// set the content type for the request
|
||||||
header.Set("Content-Type", ct)
|
header.Set("Content-Type", ct)
|
||||||
|
|
||||||
// get codec
|
// get codec
|
||||||
cf, err := h.newCodec(req.ContentType())
|
cf, err := h.newCodec(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
||||||
}
|
}
|
||||||
@@ -230,6 +223,13 @@ func (h *httpClient) stream(ctx context.Context, addr string, req client.Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpClient) newCodec(ct string) (codec.Codec, error) {
|
func (h *httpClient) newCodec(ct string) (codec.Codec, error) {
|
||||||
|
h.RLock()
|
||||||
|
defer h.RUnlock()
|
||||||
|
|
||||||
|
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||||
|
ct = ct[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
if c, ok := h.opts.Codecs[ct]; ok {
|
if c, ok := h.opts.Codecs[ct]; ok {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@ type httpRequest struct {
|
|||||||
|
|
||||||
func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...client.RequestOption) client.Request {
|
func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...client.RequestOption) client.Request {
|
||||||
options := client.NewRequestOptions(opts...)
|
options := client.NewRequestOptions(opts...)
|
||||||
|
|
||||||
if len(options.ContentType) == 0 {
|
if len(options.ContentType) == 0 {
|
||||||
options.ContentType = contentType
|
options.ContentType = contentType
|
||||||
}
|
}
|
||||||
|
39
stream.go
39
stream.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -89,7 +90,7 @@ func (h *httpStream) Recv(msg interface{}) error {
|
|||||||
}
|
}
|
||||||
defer hrsp.Body.Close()
|
defer hrsp.Body.Close()
|
||||||
|
|
||||||
return parseRsp(h.context, hrsp, h.cf, msg, h.opts)
|
return h.parseRsp(h.context, hrsp, h.cf, msg, h.opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpStream) Error() error {
|
func (h *httpStream) Error() error {
|
||||||
@@ -107,3 +108,39 @@ func (h *httpStream) Close() error {
|
|||||||
return h.conn.Close()
|
return h.conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *httpStream) parseRsp(ctx context.Context, hrsp *http.Response, cf codec.Codec, rsp interface{}, opts client.CallOptions) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// fast path return
|
||||||
|
if hrsp.StatusCode == http.StatusNoContent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if hrsp.StatusCode < 400 {
|
||||||
|
if err = cf.ReadBody(hrsp.Body, rsp); err != nil {
|
||||||
|
return errors.InternalServerError("go.micro.client", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errmap, ok := opts.Context.Value(errorMapKey{}).(map[string]interface{})
|
||||||
|
if ok && errmap != nil {
|
||||||
|
if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok {
|
||||||
|
err, ok = errmap["default"].(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
buf, err := io.ReadAll(hrsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
errors.InternalServerError("go.micro.client", err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("go.micro.client", string(buf), int32(hrsp.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cerr := cf.ReadBody(hrsp.Body, err); cerr != nil {
|
||||||
|
err = errors.InternalServerError("go.micro.client", cerr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
47
util.go
47
util.go
@@ -3,14 +3,13 @@ package http
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
|
||||||
"github.com/unistack-org/micro/v3/errors"
|
"github.com/unistack-org/micro/v3/errors"
|
||||||
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||||
util "github.com/unistack-org/micro/v3/util/router"
|
util "github.com/unistack-org/micro/v3/util/router"
|
||||||
@@ -159,36 +158,46 @@ func newTemplate(path string) (util.Template, error) {
|
|||||||
return tpl, nil
|
return tpl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRsp(ctx context.Context, hrsp *http.Response, cf codec.Codec, rsp interface{}, opts client.CallOptions) error {
|
func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp interface{}, opts client.CallOptions) error {
|
||||||
b, err := ioutil.ReadAll(hrsp.Body)
|
// fast path return
|
||||||
|
if hrsp.StatusCode == http.StatusNoContent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ct := DefaultContentType
|
||||||
|
|
||||||
|
if htype := hrsp.Header.Get("Content-Type"); htype != "" {
|
||||||
|
ct = htype
|
||||||
|
}
|
||||||
|
|
||||||
|
cf, err := h.newCodec(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InternalServerError("go.micro.client", err.Error())
|
return errors.InternalServerError("go.micro.client", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if hrsp.StatusCode < 400 {
|
if hrsp.StatusCode < 400 {
|
||||||
// unmarshal
|
if err := cf.ReadBody(hrsp.Body, rsp); err != nil {
|
||||||
if err := cf.Unmarshal(b, rsp); err != nil {
|
|
||||||
return errors.InternalServerError("go.micro.client", err.Error())
|
return errors.InternalServerError("go.micro.client", err.Error())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
errmap, ok := opts.Context.Value(errorMapKey{}).(map[string]interface{})
|
errmap, ok := opts.Context.Value(errorMapKey{}).(map[string]interface{})
|
||||||
if !ok || errmap == nil {
|
if ok && errmap != nil {
|
||||||
// user not provide map of errors
|
if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok {
|
||||||
// id: req.Service() ??
|
err, ok = errmap["default"].(error)
|
||||||
return errors.New("go.micro.client", string(b), int32(hrsp.StatusCode))
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
buf, err := io.ReadAll(hrsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
errors.InternalServerError("go.micro.client", err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("go.micro.client", string(buf), int32(hrsp.StatusCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok {
|
if cerr := cf.ReadBody(hrsp.Body, err); cerr != nil {
|
||||||
err, ok = errmap["default"].(error)
|
err = errors.InternalServerError("go.micro.client", cerr.Error())
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return errors.New("go.micro.client", string(b), int32(hrsp.StatusCode))
|
|
||||||
}
|
|
||||||
|
|
||||||
if cerr := cf.Unmarshal(b, err); cerr != nil {
|
|
||||||
return errors.InternalServerError("go.micro.client", cerr.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
Reference in New Issue
Block a user