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
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2024-05-04 16:57:40 +08:00
|
|
|
|
type HttpUtil struct {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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)后的结果
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func NewHttpUtil(log logx.Logger) *HttpUtil {
|
|
|
|
|
|
return &HttpUtil{
|
2024-04-30 17:57:27 +08:00
|
|
|
|
log: log,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get GET请求
|
|
|
|
|
|
// @param url 请求的http地址
|
|
|
|
|
|
// @param reqConfig 中header、query、body等参数
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Get(url string, reqConfig *ReqConfig) *HttpUtil {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
return h.NewRequest(http.MethodGet, url, reqConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Post POST请求
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Post(url string, reqConfig *ReqConfig) *HttpUtil {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
return h.NewRequest(http.MethodPost, url, reqConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Put PUT请求
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Put(url string, reqConfig *ReqConfig) *HttpUtil {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
return h.NewRequest(http.MethodPut, url, reqConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete DELETE请求
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Delete(url string, reqConfig *ReqConfig) *HttpUtil {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
return h.NewRequest(http.MethodDelete, url, reqConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewRequest 组装请求参数
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) NewRequest(method, url string, reqConfig *ReqConfig) (hc *HttpUtil) {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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}}...).
|
2024-05-04 16:57:40 +08:00
|
|
|
|
Errorf("[HttpUtil][NewRequest] http new request error", err)
|
2024-04-30 17:57:27 +08:00
|
|
|
|
hc.Error = err
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
hc.Request = req
|
|
|
|
|
|
// 请求参数
|
|
|
|
|
|
err = hc.requestConfig()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
hc.Error = err
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Do http请求及响应处理
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Do() (hc *HttpUtil) {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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}).
|
2024-05-04 16:57:40 +08:00
|
|
|
|
Errorf("[HttpUtil][Do] http client do error", err)
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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}).
|
2024-05-04 16:57:40 +08:00
|
|
|
|
Errorf("[HttpUtil][Do] http response ReadAll error", err)
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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后的结构
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) Result(result any) (hc *HttpUtil) {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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 {
|
2024-05-04 16:57:40 +08:00
|
|
|
|
h.log.WithFields(logx.LogField{Key: "HttpUtil", Value: hc}, logx.LogField{Key: "result", Value: result}).
|
|
|
|
|
|
Errorf("[HttpUtil][Result] http response body json unmarshal error", err)
|
2024-04-30 17:57:27 +08:00
|
|
|
|
hc.Error = err
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 请求参数
|
2024-05-04 16:57:40 +08:00
|
|
|
|
func (h *HttpUtil) requestConfig() error {
|
2024-04-30 17:57:27 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|