third-platform-sdk/util/http.go

203 lines
4.7 KiB
Go
Raw Normal View History

2024-04-30 17:57:27 +08:00
package util
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
netUrl "net/url"
"strings"
"time"
"github.com/zeromicro/go-zero/core/logx"
)
const (
TimeOut = time.Duration(30) * time.Second // http请求超时时间, 默认30s
)
type HttpClient struct {
log logx.Logger
ReqConfig *ReqConfig // 请求参数
TimeOut time.Duration // 超时时间
Request *http.Request // 请求request
Response *Response // 响应结果
Error error
}
// ReqConfig 请求参数
type ReqConfig struct {
Headers map[string]string
QueryArgs map[string]any
BodyArgs map[string]any
}
type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Header http.Header
Body []byte // body实体即io.ReadAll(resp.body)后的结果
}
func NewHttpClient(log logx.Logger) *HttpClient {
return &HttpClient{
log: log,
}
}
// Get GET请求
// @param url 请求的http地址
// @param reqConfig 中header、query、body等参数
func (h *HttpClient) Get(url string, reqConfig *ReqConfig) *HttpClient {
return h.NewRequest(http.MethodGet, url, reqConfig)
}
// Post POST请求
func (h *HttpClient) Post(url string, reqConfig *ReqConfig) *HttpClient {
return h.NewRequest(http.MethodPost, url, reqConfig)
}
// Put PUT请求
func (h *HttpClient) Put(url string, reqConfig *ReqConfig) *HttpClient {
return h.NewRequest(http.MethodPut, url, reqConfig)
}
// Delete DELETE请求
func (h *HttpClient) Delete(url string, reqConfig *ReqConfig) *HttpClient {
return h.NewRequest(http.MethodDelete, url, reqConfig)
}
// NewRequest 组装请求参数
func (h *HttpClient) NewRequest(method, url string, reqConfig *ReqConfig) (hc *HttpClient) {
if h.Error != nil {
return h
}
h.ReqConfig = reqConfig
hc = h
// 请求
req, err := http.NewRequest(method, url, nil)
if err != nil {
h.log.WithFields([]logx.LogField{{Key: "method", Value: method}, {Key: "url", Value: url}, {Key: "reqConfig", Value: reqConfig}}...).
Errorf("[HttpClient][NewRequest] http new request error", err)
hc.Error = err
return
}
hc.Request = req
// 请求参数
err = hc.requestConfig()
if err != nil {
hc.Error = err
return
}
return
}
// Do http请求及响应处理
func (h *HttpClient) Do() (hc *HttpClient) {
if h.Error != nil {
return h
}
hc = h
// http请求
timeOut := hc.TimeOut
if hc.TimeOut == 0 {
timeOut = TimeOut
}
client := &http.Client{}
client.Timeout = timeOut
// 开始请求
resp, err := client.Do(hc.Request)
if err != nil {
h.log.WithFields(logx.LogField{Key: "req", Value: hc.Request}).
Errorf("[HttpClient][Do] http client do error", err)
hc.Error = err
return
}
defer resp.Body.Close()
content, err := io.ReadAll(resp.Body)
if err != nil {
h.log.WithFields(logx.LogField{Key: "req", Value: hc.Request}).
Errorf("[HttpClient][Do] http response ReadAll error", err)
hc.Error = err
return
}
hc.Response = &Response{
Status: resp.Status,
StatusCode: resp.StatusCode,
Header: resp.Header,
Body: content,
}
return
}
// Result 获取http的响应结果
// @param result 为结构体指针类型解析http请求返回数据json.Unmarshal后的结构
func (h *HttpClient) Result(result any) (hc *HttpClient) {
if h.Error != nil {
return h
}
hc = h
if result == nil {
return
}
if hc.Response == nil || len(hc.Response.Body) == 0 {
return
}
err := json.Unmarshal(hc.Response.Body, &result)
if err != nil {
h.log.WithFields(logx.LogField{Key: "HttpClient", Value: hc}, logx.LogField{Key: "result", Value: result}).
Errorf("[HttpClient][Result] http response body json unmarshal error", err)
hc.Error = err
return
}
return
}
// 请求参数
func (h *HttpClient) requestConfig() error {
if h.Request == nil {
return errors.New("http request is nil")
}
if h.ReqConfig == nil {
return nil
}
// header参数
if h.ReqConfig.Headers != nil {
for key, value := range h.ReqConfig.Headers {
h.Request.Header.Set(key, value)
}
}
// 请求query参数
queryParams := h.Request.URL.Query()
if h.ReqConfig.QueryArgs != nil {
for key, value := range h.ReqConfig.QueryArgs {
queryParams.Add(key, fmt.Sprint(value))
}
}
h.Request.URL.RawQuery = queryParams.Encode()
// 请求body参数
if h.ReqConfig.BodyArgs != nil {
switch h.Request.Header.Get("Content-Type") {
case "application/x-www-form-urlencoded":
form := make(netUrl.Values)
for k, v := range h.ReqConfig.BodyArgs {
form.Add(k, fmt.Sprint(v))
}
h.Request.Body = io.NopCloser(strings.NewReader(form.Encode()))
case "application/json":
data, err := json.Marshal(h.ReqConfig.BodyArgs)
if err != nil {
h.Error = err
return err
}
h.Request.Body = io.NopCloser(strings.NewReader(string(data)))
}
}
return nil
}