Merge branch 'main' of ssh://git.makemake.in:5566/kzkzzzz/mycommon

main
kzkzzzz 2025-07-11 21:52:25 +08:00
commit 89708b5201
2 changed files with 119 additions and 45 deletions

View File

@ -3,7 +3,6 @@ package httpc
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"git.makemake.in/kzkzzzz/mycommon/mylog" "git.makemake.in/kzkzzzz/mycommon/mylog"
@ -21,18 +20,34 @@ var (
) )
func init() { func init() {
defaultClient = NewWithRedirect(false) defaultClient = New()
noRedirectClient = NewWithRedirect(true) noRedirectClient = New(WithNoRedirect())
} }
func NewTransport() *http.Transport { func Client() *HttpClient {
return defaultClient
}
func NoRedirectClient() *HttpClient {
return noRedirectClient
}
func NewTransport(maxConn int, idleTimeout time.Duration) *http.Transport {
if maxConn <= 0 {
panic("max connection <= 0")
}
if idleTimeout <= 0 {
panic("idle timeout <= 0")
}
tr := http.DefaultTransport.(*http.Transport).Clone() tr := http.DefaultTransport.(*http.Transport).Clone()
tr.MaxIdleConns = 0 tr.MaxIdleConns = 0
tr.MaxConnsPerHost = 0 tr.MaxConnsPerHost = 0
tr.MaxIdleConnsPerHost = 2048 tr.MaxIdleConnsPerHost = maxConn
tr.IdleConnTimeout = time.Second * 90 tr.IdleConnTimeout = idleTimeout
tr.DisableKeepAlives = false tr.DisableKeepAlives = false
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: false} //tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: false}
return tr return tr
} }
@ -46,29 +61,43 @@ type Request struct {
} }
type HttpClient struct { type HttpClient struct {
config *Config
client *http.Client client *http.Client
} }
func NewWithRedirect(noRedirect bool) *HttpClient { func New(opts ...ConfigOpt) *HttpClient {
tr := NewTransport() config := &Config{}
client := &http.Client{ for _, opt := range opts {
Transport: tr, opt(config)
Timeout: time.Second * 6,
} }
if noRedirect { if config.timeout <= 0 {
client.CheckRedirect = func(req *http.Request, via []*http.Request) error { config.timeout = time.Second * 6
return http.ErrUseLastResponse }
if config.transport == nil {
config.transport = NewTransport(3072, time.Second*90)
}
if config.client == nil {
client := &http.Client{
Transport: config.transport,
Timeout: config.timeout,
} }
if config.redirectFn != nil {
client.CheckRedirect = config.redirectFn
}
config.client = client
} }
h := &HttpClient{client: client} hc := &HttpClient{
return h config: config,
} client: config.client,
}
func NewWithClient(httpClient *http.Client) *HttpClient { return hc
h := &HttpClient{client: httpClient}
return h
} }
func (h *HttpClient) SetProxy(pr string) *HttpClient { func (h *HttpClient) SetProxy(pr string) *HttpClient {
@ -81,7 +110,7 @@ func (h *HttpClient) SetProxy(pr string) *HttpClient {
return h return h
} }
func (h *HttpClient) Request(ctx context.Context) *Request { func (h *HttpClient) NewRequest(ctx context.Context) *Request {
r := &Request{ r := &Request{
ctx: ctx, ctx: ctx,
header: nil, header: nil,
@ -91,22 +120,14 @@ func (h *HttpClient) Request(ctx context.Context) *Request {
return r return r
} }
func PcRequest(ctx context.Context) *Request { func (h *HttpClient) NewPcRequest(ctx context.Context) *Request {
return defaultClient.PcRequest(ctx) r := h.NewRequest(ctx)
}
func MobileRequest(ctx context.Context) *Request {
return defaultClient.MobileRequest(ctx)
}
func (h *HttpClient) PcRequest(ctx context.Context) *Request {
r := h.Request(ctx)
r.SetHeaderPcAgent() r.SetHeaderPcAgent()
return r return r
} }
func (h *HttpClient) MobileRequest(ctx context.Context) *Request { func (h *HttpClient) NewMobileRequest(ctx context.Context) *Request {
r := h.Request(ctx) r := h.NewRequest(ctx)
r.SetHeaderMobileAgent() r.SetHeaderMobileAgent()
return r return r
} }
@ -195,7 +216,10 @@ func (r *Request) Do(method, rawUrl string) (*Response, error) {
req.URL.RawQuery = query.Encode() req.URL.RawQuery = query.Encode()
req.Header.Set("Content-Type", r.contentType) if r.contentType != "" {
req.Header.Set("Content-Type", r.contentType)
}
for k := range r.header { for k := range r.header {
req.Header.Set(k, r.header.Get(k)) req.Header.Set(k, r.header.Get(k))
} }
@ -211,8 +235,10 @@ func (r *Request) Do(method, rawUrl string) (*Response, error) {
return nil, err return nil, err
} }
if res.StatusCode != http.StatusOK { if r.httpClient.config.noCheckStatus == false {
return nil, fmt.Errorf("status code err: %d (%s)", res.StatusCode, body) if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code err: %d (%s)", res.StatusCode, body)
}
} }
resp := &Response{ resp := &Response{
@ -223,14 +249,6 @@ func (r *Request) Do(method, rawUrl string) (*Response, error) {
return resp, nil return resp, nil
} }
func Client() *HttpClient {
return defaultClient
}
func NoRedirectClient() *HttpClient {
return noRedirectClient
}
func (r *Request) SetHeaderPcAgent() *Request { func (r *Request) SetHeaderPcAgent() *Request {
r.SetHeader(HeaderUserAgent, PcUserAgent) r.SetHeader(HeaderUserAgent, PcUserAgent)
return r return r

56
myhttp/httpc/option.go Normal file
View File

@ -0,0 +1,56 @@
package httpc
import (
"net/http"
"time"
)
type (
Config struct {
timeout time.Duration
client *http.Client
transport *http.Transport
redirectFn func(req *http.Request, via []*http.Request) error
noCheckStatus bool
}
ConfigOpt func(c *Config)
)
func WithTimout(v time.Duration) ConfigOpt {
return func(c *Config) {
c.timeout = v
}
}
func WithClient(v *http.Client) ConfigOpt {
return func(c *Config) {
c.client = v
}
}
func WithTransport(v *http.Transport) ConfigOpt {
return func(c *Config) {
c.transport = v
}
}
func WithRedirectFn(v func(req *http.Request, via []*http.Request) error) ConfigOpt {
return func(c *Config) {
c.redirectFn = v
}
}
func WithNoRedirect() ConfigOpt {
return func(c *Config) {
c.redirectFn = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
}
}
func WithNoCheckStatus(v bool) ConfigOpt {
return func(c *Config) {
c.noCheckStatus = v
}
}