This commit is contained in:
loser 2022-10-31 17:22:49 +08:00
parent 63c8b46474
commit 9f29f019ad
11 changed files with 96 additions and 99 deletions

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/14 4:11 下午 * @Date: 2021/8/14 4:11 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -29,13 +29,13 @@ type Client struct {
const ( const (
defaultUserAgent = "DobyteHttpClient" defaultUserAgent = "DobyteHttpClient"
HeaderUserAgent = "User-Agent" HeaderUserAgent = "User-Agent"
HeaderContentType = "Content-Type" HeaderContentType = "Content-Type"
HeaderAuthorization = "Authorization" HeaderAuthorization = "Authorization"
HeaderCookie = "Cookie" HeaderCookie = "Cookie"
HeaderHost = "Host" HeaderHost = "Host"
ContentTypeJson = "application/json" ContentTypeJson = "application/json"
ContentTypeXml = "application/xml" ContentTypeXml = "application/xml"
ContentTypeFormData = "form-data" ContentTypeFormData = "form-data"
@ -57,7 +57,7 @@ func NewClient() *Client {
middlewares: make([]MiddlewareFunc, 0), middlewares: make([]MiddlewareFunc, 0),
} }
client.headers[HeaderUserAgent] = defaultUserAgent client.headers[HeaderUserAgent] = defaultUserAgent
return client return client
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/16 2:54 下午 * @Date: 2021/8/16 2:54 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -10,8 +10,8 @@ package http_test
import ( import (
"errors" "errors"
"testing" "testing"
"github.com/dobyte/http" "git.echol.cn/loser/http"
) )
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlc2MiOjE2MjgwNDAzMjYxNTQ2MzIwMDAsImV4cCI6MTYyODIyMDMyNiwiaWF0IjoxNjI4MDQwMzI2LCJpZCI6MX0.KM19c6URIih-5SyycYIjNAdSiPKxMQEz3DoROm0N3nw" const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlc2MiOjE2MjgwNDAzMjYxNTQ2MzIwMDAsImV4cCI6MTYyODIyMDMyNiwiaWF0IjoxNjI4MDQwMzI2LCJpZCI6MX0.KM19c6URIih-5SyycYIjNAdSiPKxMQEz3DoROm0N3nw"
@ -23,13 +23,13 @@ func TestClient_Request(t *testing.T) {
}).Use(func(r *http.Request) (*http.Response, error) { }).Use(func(r *http.Request) (*http.Response, error) {
return nil, errors.New("Invalid params.") return nil, errors.New("Invalid params.")
}) })
resp, err := client.Request(http.MethodGet, "/common/regions") resp, err := client.Request(http.MethodGet, "/common/regions")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
t.Log(resp.Response.Status) t.Log(resp.Response.Status)
} }
@ -42,7 +42,7 @@ func TestClient_Post(t *testing.T) {
r.Request.Header.Set("Client-Type", "2") r.Request.Header.Set("Client-Type", "2")
return r.Next() return r.Next()
}) })
type updateRegionArg struct { type updateRegionArg struct {
Id int `json:"id"` Id int `json:"id"`
Pid int `json:"pid"` Pid int `json:"pid"`
@ -50,7 +50,7 @@ func TestClient_Post(t *testing.T) {
Name string `json:"name"` Name string `json:"name"`
Sort int `json:"sort"` Sort int `json:"sort"`
} }
data := updateRegionArg{ data := updateRegionArg{
Id: 1, Id: 1,
Pid: 0, Pid: 0,
@ -58,7 +58,7 @@ func TestClient_Post(t *testing.T) {
Name: "北京市", Name: "北京市",
Sort: 0, Sort: 0,
} }
if resp, err := client.Put("/backend/region/update-region", data); err != nil { if resp, err := client.Put("/backend/region/update-region", data); err != nil {
t.Error(err) t.Error(err)
return return
@ -74,7 +74,7 @@ func TestClient_Post(t *testing.T) {
func TestClient_Download(t *testing.T) { func TestClient_Download(t *testing.T) {
url := "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" url := "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
if path, err := http.NewClient().Download(url, "./"); err != nil { if path, err := http.NewClient().Download(url, "./"); err != nil {
t.Error(err) t.Error(err)
return return

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/26 1:59 下午 * @Date: 2021/8/26 1:59 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -8,10 +8,9 @@
package http package http
import ( import (
"git.echol.cn/loser/http/internal"
"os" "os"
"strings" "strings"
"github.com/dobyte/http/internal"
) )
var contentTypeToFileSuffix = map[string]string{ var contentTypeToFileSuffix = map[string]string{
@ -55,33 +54,33 @@ func (d *Download) Download(url, dir string, filename ...string) (string, error)
if err != nil { if err != nil {
return "", err return "", err
} }
var path string var path string
if len(filename) > 0 { if len(filename) > 0 {
path = strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + filename[0] path = strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + filename[0]
} else { } else {
path = d.genFilePath(resp, dir) path = d.genFilePath(resp, dir)
} }
if err = internal.SaveToFile(path, resp.ReadBytes()); err != nil { if err = internal.SaveToFile(path, resp.ReadBytes()); err != nil {
return "", err return "", err
} }
return path, nil return path, nil
} }
// genFilePath generate file path based on response content type // genFilePath generate file path based on response content type
func (d *Download) genFilePath(resp *Response, dir string) string { func (d *Download) genFilePath(resp *Response, dir string) string {
path := strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + internal.RandStr(16) path := strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + internal.RandStr(16)
if suffix := internal.GetFileType(resp.ReadBytes()); suffix != "" { if suffix := internal.GetFileType(resp.ReadBytes()); suffix != "" {
path += "." + suffix path += "." + suffix
} }
if internal.Exists(path) { if internal.Exists(path) {
return d.genFilePath(resp, dir) return d.genFilePath(resp, dir)
} }
return path return path
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/26 5:00 下午 * @Date: 2021/8/26 5:00 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -68,20 +68,20 @@ func String(any interface{}) string {
if v == nil { if v == nil {
return "" return ""
} }
if i, ok := v.(stringInterface); ok { if i, ok := v.(stringInterface); ok {
return i.String() return i.String()
} }
if i, ok := v.(errorInterface); ok { if i, ok := v.(errorInterface); ok {
return i.Error() return i.Error()
} }
var ( var (
rv = reflect.ValueOf(v) rv = reflect.ValueOf(v)
kind = rv.Kind() kind = rv.Kind()
) )
switch kind { switch kind {
case reflect.Chan, case reflect.Chan,
reflect.Map, reflect.Map,
@ -96,11 +96,11 @@ func String(any interface{}) string {
case reflect.String: case reflect.String:
return rv.String() return rv.String()
} }
if kind == reflect.Ptr { if kind == reflect.Ptr {
return String(rv.Elem().Interface()) return String(rv.Elem().Interface())
} }
if b, e := json.Marshal(v); e != nil { if b, e := json.Marshal(v); e != nil {
return fmt.Sprint(v) return fmt.Sprint(v)
} else { } else {
@ -211,16 +211,16 @@ func Scan(b []byte, any interface{}) error {
rv = reflect.ValueOf(v) rv = reflect.ValueOf(v)
kind = rv.Kind() kind = rv.Kind()
) )
if kind != reflect.Ptr { if kind != reflect.Ptr {
return fmt.Errorf("can't unmarshal %T", v) return fmt.Errorf("can't unmarshal %T", v)
} }
switch kind = rv.Elem().Kind(); kind { switch kind = rv.Elem().Kind(); kind {
case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct: case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct:
return json.Unmarshal(b, v) return json.Unmarshal(b, v)
} }
return fmt.Errorf("can't unmarshal %T", v) return fmt.Errorf("can't unmarshal %T", v)
} }
} }
@ -231,4 +231,4 @@ func UnsafeStringToBytes(s string) []byte {
func UnsafeBytesToString(b []byte) string { func UnsafeBytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) return *(*string)(unsafe.Pointer(&b))
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/26 4:59 下午 * @Date: 2021/8/26 4:59 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -29,19 +29,19 @@ func SaveToFile(path string, data []byte) error {
return err return err
} }
} }
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0666)) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0666))
if err != nil { if err != nil {
return err return err
} }
defer f.Close() defer f.Close()
if n, err := f.Write(data); err != nil { if n, err := f.Write(data); err != nil {
return err return err
} else if n < len(data) { } else if n < len(data) {
return io.ErrShortWrite return io.ErrShortWrite
} }
return nil return nil
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/26 4:51 下午 * @Date: 2021/8/26 4:51 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -17,12 +17,12 @@ var seedStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// RandStr generate a string of specified length. // RandStr generate a string of specified length.
func RandStr(length int) (lastStr string) { func RandStr(length int) (lastStr string) {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
pos, seedLen := 0, len(seedStr) pos, seedLen := 0, len(seedStr)
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
pos = rand.Intn(seedLen) pos = rand.Intn(seedLen)
lastStr += seedStr[pos : pos+1] lastStr += seedStr[pos : pos+1]
} }
return lastStr return lastStr
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/26 6:21 下午 * @Date: 2021/8/26 6:21 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -81,21 +81,21 @@ func bytesToHexString(stream []byte) string {
if stream == nil || len(stream) <= 0 { if stream == nil || len(stream) <= 0 {
return "" return ""
} }
var ( var (
hv string hv string
res = bytes.Buffer{} res = bytes.Buffer{}
temp = make([]byte, 0) temp = make([]byte, 0)
) )
for _, v := range stream { for _, v := range stream {
if hv = hex.EncodeToString(append(temp, v&0xFF)); len(hv) < 2 { if hv = hex.EncodeToString(append(temp, v&0xFF)); len(hv) < 2 {
res.WriteString(strconv.FormatInt(int64(0), 10)) res.WriteString(strconv.FormatInt(int64(0), 10))
} }
res.WriteString(hv) res.WriteString(hv)
} }
return res.String() return res.String()
} }
@ -105,16 +105,16 @@ func GetFileType(stream []byte) string {
fileType string fileType string
fileCode = bytesToHexString(stream) fileCode = bytesToHexString(stream)
) )
fileTypeMap.Range(func(key, value interface{}) bool { fileTypeMap.Range(func(key, value interface{}) bool {
if strings.HasPrefix(fileCode, strings.ToLower(key.(string))) || if strings.HasPrefix(fileCode, strings.ToLower(key.(string))) ||
strings.HasPrefix(key.(string), strings.ToLower(fileCode)) { strings.HasPrefix(key.(string), strings.ToLower(fileCode)) {
fileType = value.(string) fileType = value.(string)
return false return false
} }
return true return true
}) })
return fileType return fileType
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/16 3:47 下午 * @Date: 2021/8/16 3:47 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -28,9 +28,9 @@ func BuildParams(params interface{}) string {
params = nil params = nil
} }
} }
m := make(map[string]interface{}) m := make(map[string]interface{})
if params != nil { if params != nil {
if b, err := json.Marshal(params); err != nil { if b, err := json.Marshal(params); err != nil {
return String(params) return String(params)
@ -40,25 +40,25 @@ func BuildParams(params interface{}) string {
} else { } else {
return "" return ""
} }
urlEncode := true urlEncode := true
if len(m) == 0 { if len(m) == 0 {
return String(params) return String(params)
} }
for k, v := range m { for k, v := range m {
if strings.Contains(k, fileUploadingKey) || strings.Contains(String(v), fileUploadingKey) { if strings.Contains(k, fileUploadingKey) || strings.Contains(String(v), fileUploadingKey) {
urlEncode = false urlEncode = false
break break
} }
} }
var ( var (
s = "" s = ""
str = "" str = ""
) )
for k, v := range m { for k, v := range m {
if len(str) > 0 { if len(str) > 0 {
str += "&" str += "&"
@ -69,6 +69,6 @@ func BuildParams(params interface{}) string {
} }
str += k + "=" + s str += k + "=" + s
} }
return str return str
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/16 9:47 上午 * @Date: 2021/8/16 9:47 上午
* @Desc: request's middleware * @Desc: request's middleware
*/ */
@ -27,6 +27,6 @@ func (m *middleware) Next() (*Response, error) {
return m.resp, m.err return m.resp, m.err
} }
} }
return m.resp, m.err return m.resp, m.err
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/16 9:40 上午 * @Date: 2021/8/16 9:40 上午
* @Desc: TODO * @Desc: TODO
*/ */
@ -14,6 +14,7 @@ import (
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
"git.echol.cn/loser/http/internal"
"io" "io"
"log" "log"
"mime/multipart" "mime/multipart"
@ -23,8 +24,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"time" "time"
"github.com/dobyte/http/internal"
) )
const ( const (
@ -70,7 +69,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
if err != nil { if err != nil {
return nil, err return nil, err
} }
if count := len(r.client.middlewares); count > 0 { if count := len(r.client.middlewares); count > 0 {
handlers := make([]MiddlewareFunc, 0, count+1) handlers := make([]MiddlewareFunc, 0, count+1)
handlers = append(handlers, r.client.middlewares...) handlers = append(handlers, r.client.middlewares...)
@ -86,7 +85,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
} else { } else {
resp, err = r.call() resp, err = r.call()
} }
return resp, err return resp, err
} }
@ -94,7 +93,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Request, err error) { func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Request, err error) {
method = strings.ToUpper(method) method = strings.ToUpper(method)
url = r.client.baseUrl + url url = r.client.baseUrl + url
var params string var params string
if len(data) > 0 { if len(data) > 0 {
switch data[0].(type) { switch data[0].(type) {
@ -121,10 +120,10 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
} }
} }
if method == MethodGet { if method == MethodGet {
buffer := bytes.NewBuffer(nil) buffer := bytes.NewBuffer(nil)
if params != "" { if params != "" {
switch r.client.headers[HeaderContentType] { switch r.client.headers[HeaderContentType] {
case ContentTypeJson, ContentTypeXml: case ContentTypeJson, ContentTypeXml:
@ -137,7 +136,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
} }
} }
if req, err = http.NewRequest(method, url, buffer); err != nil { if req, err = http.NewRequest(method, url, buffer); err != nil {
return nil, err return nil, err
} }
@ -147,7 +146,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
buffer = bytes.NewBuffer(nil) buffer = bytes.NewBuffer(nil)
writer = multipart.NewWriter(buffer) writer = multipart.NewWriter(buffer)
) )
for _, item := range strings.Split(params, "&") { for _, item := range strings.Split(params, "&") {
array := strings.Split(item, "=") array := strings.Split(item, "=")
if len(array[1]) > 6 && strings.Compare(array[1][0:6], fileUploadingKey) == 0 { if len(array[1]) > 6 && strings.Compare(array[1][0:6], fileUploadingKey) == 0 {
@ -178,11 +177,11 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
} }
} }
if err = writer.Close(); err != nil { if err = writer.Close(); err != nil {
return nil, err return nil, err
} }
if req, err = http.NewRequest(method, url, buffer); err != nil { if req, err = http.NewRequest(method, url, buffer); err != nil {
return nil, err return nil, err
} else { } else {
@ -205,13 +204,13 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
} }
} }
if r.client.ctx != nil { if r.client.ctx != nil {
req = req.WithContext(r.client.ctx) req = req.WithContext(r.client.ctx)
} else { } else {
req = req.WithContext(context.Background()) req = req.WithContext(context.Background())
} }
if len(r.client.headers) > 0 { if len(r.client.headers) > 0 {
for key, value := range r.client.headers { for key, value := range r.client.headers {
if key != "" { if key != "" {
@ -219,7 +218,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
} }
} }
if len(r.client.cookies) > 0 { if len(r.client.cookies) > 0 {
var cookies = make([]string, 0) var cookies = make([]string, 0)
for key, value := range r.client.cookies { for key, value := range r.client.cookies {
@ -229,18 +228,18 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
} }
req.Header.Set(HeaderCookie, strings.Join(cookies, ";")) req.Header.Set(HeaderCookie, strings.Join(cookies, ";"))
} }
if host := req.Header.Get(HeaderHost); host != "" { if host := req.Header.Get(HeaderHost); host != "" {
req.Host = host req.Host = host
} }
return req, nil return req, nil
} }
// call nitiate an HTTP request and return the response data. // call nitiate an HTTP request and return the response data.
func (r *Request) call() (resp *Response, err error) { func (r *Request) call() (resp *Response, err error) {
resp = &Response{Request: r.Request} resp = &Response{Request: r.Request}
for { for {
if resp.Response, err = r.client.Do(r.Request); err != nil { if resp.Response, err = r.client.Do(r.Request); err != nil {
if resp.Response != nil { if resp.Response != nil {
@ -248,7 +247,7 @@ func (r *Request) call() (resp *Response, err error) {
log.Printf(`%+v`, err) log.Printf(`%+v`, err)
} }
} }
if r.retryCount > 0 { if r.retryCount > 0 {
r.retryCount-- r.retryCount--
time.Sleep(r.retryInterval) time.Sleep(r.retryInterval)
@ -259,6 +258,6 @@ func (r *Request) call() (resp *Response, err error) {
break break
} }
} }
return resp, err return resp, err
} }

View File

@ -1,6 +1,6 @@
/** /**
* @Author: fuxiao * @Author: Echo
* @Email: 576101059@qq.com * @Email: 1711788888@qq.com
* @Date: 2021/8/15 4:56 下午 * @Date: 2021/8/15 4:56 下午
* @Desc: TODO * @Desc: TODO
*/ */
@ -8,11 +8,10 @@
package http package http
import ( import (
"git.echol.cn/loser/http/internal"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"sync" "sync"
"github.com/dobyte/http/internal"
) )
type Response struct { type Response struct {
@ -28,7 +27,7 @@ func (r *Response) ReadBytes() []byte {
if r == nil || r.Response == nil { if r == nil || r.Response == nil {
return []byte{} return []byte{}
} }
if r.body == nil { if r.body == nil {
var err error var err error
r.mu.Lock() r.mu.Lock()
@ -37,7 +36,7 @@ func (r *Response) ReadBytes() []byte {
return nil return nil
} }
} }
return r.body return r.body
} }
@ -67,7 +66,7 @@ func (r *Response) HasHeader(key string) bool {
return true return true
} }
} }
return false return false
} }
@ -86,7 +85,7 @@ func (r *Response) GetHeaders() map[string]interface{} {
headers[k] = v[0] headers[k] = v[0]
} }
} }
return headers return headers
} }
@ -96,7 +95,7 @@ func (r *Response) HasCookie(key string) bool {
r.cookies = r.GetCookies() r.cookies = r.GetCookies()
} }
_, ok := r.cookies[key] _, ok := r.cookies[key]
return ok return ok
} }