123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package fetch
- import (
- "bytes"
- "context"
- "crypto/tls"
- "encoding/json"
- "encoding/xml"
- "fmt"
- "io"
- "net"
- "net/http"
- "net/url"
- "strings"
- "time"
- )
- var (
- httpClient = http.Client{
- Timeout: time.Second * 15,
- Transport: &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- TLSClientConfig: &tls.Config{
- InsecureSkipVerify: true,
- },
- DialContext: (&net.Dialer{
- Timeout: 30 * time.Second,
- KeepAlive: 30 * time.Second,
- }).DialContext,
- ForceAttemptHTTP2: false,
- MaxIdleConns: 10,
- IdleConnTimeout: 30 * time.Second,
- TLSHandshakeTimeout: 10 * time.Second,
- ExpectContinueTimeout: 1 * time.Second,
- },
- }
- )
- func Get(ctx context.Context, urlString string, cbs ...Option) (res *http.Response, err error) {
- var (
- uri *url.URL
- req *http.Request
- )
- opts := newOptions()
- for _, cb := range cbs {
- cb(opts)
- }
- if uri, err = url.Parse(urlString); err != nil {
- return
- }
- if opts.Params != nil {
- qs := uri.Query()
- for k, v := range opts.Params {
- qs.Set(k, v)
- }
- uri.RawQuery = qs.Encode()
- }
- if req, err = http.NewRequest(http.MethodGet, uri.String(), nil); err != nil {
- return
- }
- if opts.Header != nil {
- for k, v := range opts.Header {
- req.Header.Set(k, v)
- }
- }
- return Do(ctx, req)
- }
- func Post(ctx context.Context, urlString string, cbs ...Option) (res *http.Response, err error) {
- var (
- buf []byte
- uri *url.URL
- req *http.Request
- contentType string
- reader io.Reader
- )
- opts := newOptions()
- for _, cb := range cbs {
- cb(opts)
- }
- if uri, err = url.Parse(urlString); err != nil {
- return
- }
- if opts.Params != nil {
- qs := uri.Query()
- for k, v := range opts.Params {
- qs.Set(k, v)
- }
- uri.RawQuery = qs.Encode()
- }
- if opts.Data != nil {
- switch v := opts.Data.(type) {
- case string:
- reader = strings.NewReader(v)
- contentType = "x-www-form-urlencoded"
- case []byte:
- reader = bytes.NewReader(v)
- contentType = "x-www-form-urlencoded"
- default:
- if buf, err = json.Marshal(v); err == nil {
- reader = bytes.NewReader(buf)
- contentType = "application/json"
- } else {
- return
- }
- }
- }
- if req, err = http.NewRequest(http.MethodPost, uri.String(), reader); err != nil {
- return
- }
- if opts.Header != nil {
- for k, v := range opts.Header {
- req.Header.Set(k, v)
- }
- }
- req.Header.Set("Content-Type", contentType)
- return Do(ctx, req)
- }
- func Do(ctx context.Context, req *http.Request) (res *http.Response, err error) {
- return httpClient.Do(req.WithContext(ctx))
- }
- func Request(ctx context.Context, urlString string, response any, cbs ...Option) (err error) {
- var (
- buf []byte
- uri *url.URL
- res *http.Response
- req *http.Request
- contentType string
- )
- opts := newOptions()
- for _, cb := range cbs {
- cb(opts)
- }
- if uri, err = url.Parse(urlString); err != nil {
- return
- }
- if opts.Params != nil {
- qs := uri.Query()
- for k, v := range opts.Params {
- qs.Set(k, v)
- }
- uri.RawQuery = qs.Encode()
- }
- if req, err = http.NewRequest(http.MethodGet, uri.String(), nil); err != nil {
- return
- }
- if opts.Header != nil {
- for k, v := range opts.Header {
- req.Header.Set(k, v)
- }
- }
- if res, err = Do(ctx, req); err != nil {
- return
- }
- defer func() {
- _ = res.Body.Close()
- }()
- if res.StatusCode != http.StatusOK {
- if buf, err = io.ReadAll(res.Body); err == nil && len(buf) > 0 {
- err = fmt.Errorf("remote server response %s(%d): %s", res.Status, res.StatusCode, string(buf))
- } else {
- err = fmt.Errorf("remote server response %d: %s", res.StatusCode, res.Status)
- }
- return
- }
- contentType = strings.ToLower(res.Header.Get("Content-Type"))
- if strings.Contains(contentType, JSON) {
- err = json.NewDecoder(res.Body).Decode(response)
- } else if strings.Contains(contentType, XML) {
- err = xml.NewDecoder(res.Body).Decode(response)
- } else {
- err = fmt.Errorf("unsupported content type: %s", contentType)
- }
- return
- }
|