github.com/lingyao2333/mo-zero@v1.4.1/rest/httpc/service.go (about)

     1  package httpc
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  
     7  	"github.com/lingyao2333/mo-zero/core/breaker"
     8  )
     9  
    10  type (
    11  	// Option is used to customize the *http.Client.
    12  	Option func(r *http.Request) *http.Request
    13  
    14  	// Service represents a remote HTTP service.
    15  	Service interface {
    16  		// Do sends an HTTP request with the given arguments and returns an HTTP response.
    17  		Do(ctx context.Context, method, url string, data interface{}) (*http.Response, error)
    18  		// DoRequest sends a HTTP request to the service.
    19  		DoRequest(r *http.Request) (*http.Response, error)
    20  	}
    21  
    22  	namedService struct {
    23  		name string
    24  		cli  *http.Client
    25  		opts []Option
    26  	}
    27  )
    28  
    29  // NewService returns a remote service with the given name.
    30  // opts are used to customize the *http.Client.
    31  func NewService(name string, opts ...Option) Service {
    32  	return NewServiceWithClient(name, http.DefaultClient, opts...)
    33  }
    34  
    35  // NewServiceWithClient returns a remote service with the given name.
    36  // opts are used to customize the *http.Client.
    37  func NewServiceWithClient(name string, cli *http.Client, opts ...Option) Service {
    38  	return namedService{
    39  		name: name,
    40  		cli:  cli,
    41  		opts: opts,
    42  	}
    43  }
    44  
    45  // Do sends an HTTP request with the given arguments and returns an HTTP response.
    46  func (s namedService) Do(ctx context.Context, method, url string, data interface{}) (*http.Response, error) {
    47  	req, err := buildRequest(ctx, method, url, data)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	return s.DoRequest(req)
    53  }
    54  
    55  // DoRequest sends an HTTP request to the service.
    56  func (s namedService) DoRequest(r *http.Request) (*http.Response, error) {
    57  	return request(r, s)
    58  }
    59  
    60  func (s namedService) do(r *http.Request) (resp *http.Response, err error) {
    61  	for _, opt := range s.opts {
    62  		r = opt(r)
    63  	}
    64  
    65  	brk := breaker.GetBreaker(s.name)
    66  	err = brk.DoWithAcceptable(func() error {
    67  		resp, err = s.cli.Do(r)
    68  		return err
    69  	}, func(err error) bool {
    70  		return err == nil && resp.StatusCode < http.StatusInternalServerError
    71  	})
    72  
    73  	return
    74  }