third-platform-sdk/util/http.go
2024-04-30 17:57:27 +08:00

203 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}