204 lines
4.7 KiB
Go
204 lines
4.7 KiB
Go
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 HttpUtil 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 NewHttpUtil(log logx.Logger) *HttpUtil {
|
||
return &HttpUtil{
|
||
log: log,
|
||
}
|
||
}
|
||
|
||
// Get GET请求
|
||
// @param url 请求的http地址
|
||
// @param reqConfig 中header、query、body等参数
|
||
func (h *HttpUtil) Get(url string, reqConfig *ReqConfig) *HttpUtil {
|
||
return h.NewRequest(http.MethodGet, url, reqConfig)
|
||
}
|
||
|
||
// Post POST请求
|
||
func (h *HttpUtil) Post(url string, reqConfig *ReqConfig) *HttpUtil {
|
||
return h.NewRequest(http.MethodPost, url, reqConfig)
|
||
}
|
||
|
||
// Put PUT请求
|
||
func (h *HttpUtil) Put(url string, reqConfig *ReqConfig) *HttpUtil {
|
||
return h.NewRequest(http.MethodPut, url, reqConfig)
|
||
}
|
||
|
||
// Delete DELETE请求
|
||
func (h *HttpUtil) Delete(url string, reqConfig *ReqConfig) *HttpUtil {
|
||
return h.NewRequest(http.MethodDelete, url, reqConfig)
|
||
}
|
||
|
||
// NewRequest 组装请求参数
|
||
func (h *HttpUtil) NewRequest(method, url string, reqConfig *ReqConfig) (hc *HttpUtil) {
|
||
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("[HttpUtil][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 *HttpUtil) Do() (hc *HttpUtil) {
|
||
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("[HttpUtil][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("[HttpUtil][Do] http response ReadAll error", err)
|
||
hc.Error = err
|
||
return
|
||
}
|
||
fmt.Printf("===== http response content: %s\n", content)
|
||
hc.Response = &Response{
|
||
Status: resp.Status,
|
||
StatusCode: resp.StatusCode,
|
||
Header: resp.Header,
|
||
Body: content,
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// Result 获取http的响应结果
|
||
// @param result 为结构体(指针类型),解析http请求返回数据json.Unmarshal后的结构
|
||
func (h *HttpUtil) Result(result any) (hc *HttpUtil) {
|
||
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: "HttpUtil", Value: hc}, logx.LogField{Key: "result", Value: result}).
|
||
Errorf("[HttpUtil][Result] http response body json unmarshal error", err)
|
||
hc.Error = err
|
||
return
|
||
}
|
||
return
|
||
}
|
||
|
||
// 请求参数
|
||
func (h *HttpUtil) 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
|
||
}
|