update
parent
e42de5e171
commit
27ccc2a080
|
@ -0,0 +1,19 @@
|
||||||
|
package httpc
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderUserAgent = "User-Agent"
|
||||||
|
HeaderContentType = "Content-Type"
|
||||||
|
HeaderCookie = "Cookie"
|
||||||
|
HeaderAccept = "Accept"
|
||||||
|
HeaderOrigin = "Origin"
|
||||||
|
HeaderReferer = "Referer"
|
||||||
|
HeaderAcceptLanguage = "Accept-Language"
|
||||||
|
|
||||||
|
ContentTypeJSON = "application/json; charset=utf-8"
|
||||||
|
)
|
||||||
|
const (
|
||||||
|
MobileUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/124.0.6367.68 MobileRequest/15E148 Safari/604.1"
|
||||||
|
PcUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
|
||||||
|
AcceptHtml = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
|
||||||
|
AcceptCNLanguage = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||||||
|
)
|
|
@ -0,0 +1,276 @@
|
||||||
|
package httpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"git.makemake.in/kzkzzzz/mycommon/mylog"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultClient *HttpClient
|
||||||
|
noRedirectClient *HttpClient
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
defaultClient = NewWithRedirect(false)
|
||||||
|
noRedirectClient = NewWithRedirect(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransport() *http.Transport {
|
||||||
|
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
tr.MaxIdleConns = 0
|
||||||
|
tr.MaxConnsPerHost = 0
|
||||||
|
tr.MaxIdleConnsPerHost = 2048
|
||||||
|
tr.IdleConnTimeout = time.Second * 90
|
||||||
|
tr.DisableKeepAlives = false
|
||||||
|
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: false}
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
ctx context.Context
|
||||||
|
header http.Header
|
||||||
|
body any
|
||||||
|
query map[string]string
|
||||||
|
httpClient *HttpClient
|
||||||
|
contentType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpClient struct {
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithRedirect(noRedirect bool) *HttpClient {
|
||||||
|
tr := NewTransport()
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: tr,
|
||||||
|
Timeout: time.Second * 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
if noRedirect {
|
||||||
|
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &HttpClient{client: client}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithClient(httpClient *http.Client) *HttpClient {
|
||||||
|
h := &HttpClient{client: httpClient}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpClient) SetProxy(pr string) *HttpClient {
|
||||||
|
u, err := url.Parse(pr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.client.Transport.(*http.Transport).Proxy = http.ProxyURL(u)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpClient) Request(ctx context.Context) *Request {
|
||||||
|
r := &Request{
|
||||||
|
ctx: ctx,
|
||||||
|
header: nil,
|
||||||
|
query: nil,
|
||||||
|
httpClient: h,
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func PcRequest(ctx context.Context) *Request {
|
||||||
|
return defaultClient.PcRequest(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()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpClient) MobileRequest(ctx context.Context) *Request {
|
||||||
|
r := h.Request(ctx)
|
||||||
|
r.SetHeaderMobileAgent()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetContentType(contentType string) *Request {
|
||||||
|
r.contentType = contentType
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetBody(body any) *Request {
|
||||||
|
r.body = body
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetQueryParam(k, v string) *Request {
|
||||||
|
if r.query == nil {
|
||||||
|
r.query = make(map[string]string)
|
||||||
|
}
|
||||||
|
r.query[k] = v
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetQueryParams(params map[string]string) *Request {
|
||||||
|
for k, v := range params {
|
||||||
|
r.SetQueryParam(k, v)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetHeader(k, v string) *Request {
|
||||||
|
if r.header == nil {
|
||||||
|
r.header = http.Header{}
|
||||||
|
}
|
||||||
|
r.header.Set(k, v)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetHeaders(headers map[string]string) *Request {
|
||||||
|
for k, v := range headers {
|
||||||
|
r.SetHeader(k, v)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Get(rawUrl string) (*Response, error) {
|
||||||
|
return r.Do(http.MethodGet, rawUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Post(rawUrl string) (*Response, error) {
|
||||||
|
return r.Do(http.MethodPost, rawUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Do(method, rawUrl string) (*Response, error) {
|
||||||
|
reqUrl, err := url.Parse(rawUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqBody io.Reader = nil
|
||||||
|
if r.body != nil {
|
||||||
|
switch v := r.body.(type) {
|
||||||
|
case string:
|
||||||
|
reqBody = strings.NewReader(v)
|
||||||
|
case []byte:
|
||||||
|
reqBody = bytes.NewReader(v)
|
||||||
|
|
||||||
|
default:
|
||||||
|
marshal, err := jsoniter.Marshal(r.body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reqBody = bytes.NewReader(marshal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, reqUrl.String(), reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := req.URL.Query()
|
||||||
|
|
||||||
|
for k, v := range r.query {
|
||||||
|
query.Add(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", r.contentType)
|
||||||
|
for k := range r.header {
|
||||||
|
req.Header.Set(k, r.header.Get(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := r.httpClient.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("status code err: %d (%s)", res.StatusCode, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Response{
|
||||||
|
body: body,
|
||||||
|
Response: res,
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Client() *HttpClient {
|
||||||
|
return defaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NoRedirectClient() *HttpClient {
|
||||||
|
return noRedirectClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetHeaderPcAgent() *Request {
|
||||||
|
r.SetHeader(HeaderUserAgent, PcUserAgent)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetHeaderMobileAgent() *Request {
|
||||||
|
r.SetHeader(HeaderUserAgent, MobileUserAgent)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) SetHeaderAcceptHtml() *Request {
|
||||||
|
r.SetHeader(HeaderAccept, AcceptHtml)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) GetRedirectUrl(reqUrl string) (
|
||||||
|
*url.URL, *Response, error) {
|
||||||
|
|
||||||
|
//r.SetDebug(true)
|
||||||
|
r.SetHeaderAcceptHtml()
|
||||||
|
resp, err := r.Get(reqUrl)
|
||||||
|
|
||||||
|
if err != nil && !errors.Is(err, http.ErrUseLastResponse) {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
location, err := resp.Response.Location()
|
||||||
|
if err != nil {
|
||||||
|
mylog.Warnf("location code: %v", resp.Response.StatusCode)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return location, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
body []byte
|
||||||
|
Response *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) GetBody() []byte {
|
||||||
|
return r.body
|
||||||
|
}
|
Loading…
Reference in New Issue