粗略实现了一下 requests 库。但后来想想,也必要自己造轮子,还是 resty 香!

package requests

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

type Client struct {
	Url     string
	Headers map[string][]string
	Params  map[string][]string
	Content string
	Data    interface{}
	Json    interface{}
}

type Response struct {
	Status     string
	StatusCode int
	Body       string
}

func (c Client) newRequest(method string) (req *http.Request, err error) {
	// url
	if reflect.ValueOf(c.Url).IsZero() {
		err = errors.New(fmt.Sprintf("url is needed: client=%+v", c))
		return
	}
	u, err := url.ParseRequestURI(c.Url)
	if err != nil {
		return
	}

	// params
	if !reflect.ValueOf(c.Params).IsNil() {
		var params url.Values = c.Params
		u.RawQuery = params.Encode()
	}

	// body, headers
	body := ""
	if reflect.ValueOf(c.Headers).IsNil() {
		c.Headers = make(map[string][]string)
	}
	if !reflect.ValueOf(c.Content).IsZero() {
		body = c.Content
	} else if !reflect.ValueOf(c.Data).IsValid() {
		c.Headers["Content-Type"] = []string{"application/x-www-form-urlencoded"}
		var bodyBytes []byte
		bodyBytes, err = json.Marshal(c.Json)
		if err != nil {
			return
		}
		body = string(bodyBytes)
	} else if !reflect.ValueOf(c.Json).IsValid() {
		c.Headers["Content-Type"] = []string{"application/json"}
		var bodyBytes []byte
		bodyBytes, err = json.Marshal(c.Json)
		if err != nil {
			return
		}
		body = string(bodyBytes)
	}

	req, err = http.NewRequest(method, u.String(), strings.NewReader(body))
	if err != nil {
		return
	}
	req.Header = c.Headers
	return
}

func (c Client) parseResponse(resp *http.Response) (response *Response, err error) {
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			log.Printf("close response body failed: err=%s", err)
		}
	}(resp.Body)
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return
	}
	return &Response{
		resp.Status,
		resp.StatusCode,
		string(body),
	}, nil
}

func (c Client) Request(method string) (response *Response, err error) {
	req, err := c.newRequest(method)
	if err != nil {
		return
	}
	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	return c.parseResponse(resp)
}

func (c Client) Get() (response *Response, err error) {
	return c.Request("GET")
}

func (c Client) Post() (response *Response, err error) {
	return c.Request("POST")
}