Files
wk-backend/pkg/request/client.go

120 lines
3.0 KiB
Go

package request
import (
"crypto/tls"
"encoding/json"
"net/http"
"time"
"ckwk/pkg/log"
"go.uber.org/zap/zapcore"
"resty.dev/v3"
)
var (
NoRedirectClient *resty.Client
RestyClient *resty.Client
)
const (
DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0"
DefaultTimeout = 10 * time.Second
DefaultDebugBody = 4 * 1024
)
type Config struct {
Timeout time.Duration
Proxy string
Debug bool
UserAgent string
VerifySSL bool
}
func DefaultConfg() *Config {
return &Config{
Timeout: DefaultTimeout,
UserAgent: DefaultUserAgent,
VerifySSL: true,
Debug: false,
}
}
// NewClient 创建一个标准的 Resty 客户端
func NewClient(cfg *Config) *resty.Client {
defaults := DefaultConfg()
if cfg == nil {
cfg = defaults
} else {
// 合并零值,避免调用方只覆盖部分字段时丢失默认超时和 User-Agent。
if cfg.Timeout <= 0 {
cfg.Timeout = defaults.Timeout
}
if cfg.UserAgent == "" {
cfg.UserAgent = defaults.UserAgent
}
}
client := resty.New()
client.SetHeader("User-Agent", cfg.UserAgent)
client.SetTimeout(cfg.Timeout)
client.SetRetryCount(3)
client.SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: !cfg.VerifySSL,
})
if cfg.Proxy != "" {
client.SetProxy(cfg.Proxy)
}
if cfg.Debug {
client.SetDebug(true)
client.SetDebugBodyLimit(DefaultDebugBody)
client.OnDebugLog(func(debugLog *resty.DebugLog) {
fields := map[string]any{
"request": map[string]any{
"host": debugLog.Request.Host,
"uri": debugLog.Request.URI,
"method": debugLog.Request.Method,
"proto": debugLog.Request.Proto,
"header": log.SanitizeHeaders(debugLog.Request.Header),
"attempt": debugLog.Request.Attempt,
"body": log.SanitizeBody(debugLog.Request.Header.Get("Content-Type"), debugLog.Request.Body),
},
"response": map[string]any{
"statusCode": debugLog.Response.StatusCode,
"status": debugLog.Response.Status,
"proto": debugLog.Response.Proto,
"receivedAt": debugLog.Response.ReceivedAt.Format(time.RFC3339Nano),
"durationMs": debugLog.Response.Duration.Milliseconds(),
"size": debugLog.Response.Size,
"header": log.SanitizeHeaders(debugLog.Response.Header),
"body": log.SanitizeBody(debugLog.Response.Header.Get("Content-Type"), debugLog.Response.Body),
},
}
if debugLog.TraceInfo != nil {
if traceJSON, err := json.Marshal(debugLog.TraceInfo); err == nil {
fields["trace"] = json.RawMessage(traceJSON)
}
}
log.Capture(zapcore.DebugLevel, "resty", "outbound exchange", fields)
})
client.SetDebugLogFormatter(nil)
}
return client
}
// NewNoRedirectClient 创建一个禁止重定向的客户端
func NewNoRedirectClient(cfg *Config) *resty.Client {
client := NewClient(cfg)
client.SetRedirectPolicy(
resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}),
)
return client
}