first commit
This commit is contained in:
264
request.go
Normal file
264
request.go
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Date: 2021/8/16 9:40 上午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dobyte/http/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
MethodGet = http.MethodGet
|
||||
MethodHead = http.MethodHead
|
||||
MethodPost = http.MethodPost
|
||||
MethodPut = http.MethodPut
|
||||
MethodPatch = http.MethodPatch
|
||||
MethodDelete = http.MethodDelete
|
||||
MethodConnect = http.MethodConnect
|
||||
MethodOptions = http.MethodOptions
|
||||
MethodTrace = http.MethodTrace
|
||||
)
|
||||
|
||||
const fileUploadingKey = "@file:"
|
||||
|
||||
type Request struct {
|
||||
client *Client
|
||||
retryCount int
|
||||
retryInterval time.Duration
|
||||
Request *http.Request
|
||||
}
|
||||
|
||||
func NewRequest(c *Client) *Request {
|
||||
return &Request{
|
||||
client: c,
|
||||
retryCount: c.retryCount,
|
||||
retryInterval: c.retryInterval,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) Next() (*Response, error) {
|
||||
if v := r.Request.Context().Value(middlewareKey); v != nil {
|
||||
if m, ok := v.(*middleware); ok {
|
||||
return m.Next()
|
||||
}
|
||||
}
|
||||
return r.call()
|
||||
}
|
||||
|
||||
func (r *Request) request(method, url string, data ...interface{}) (resp *Response, err error) {
|
||||
r.Request, err = r.prepare(method, url, data...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if count := len(r.client.middlewares); count > 0 {
|
||||
handlers := make([]MiddlewareFunc, 0, count+1)
|
||||
handlers = append(handlers, r.client.middlewares...)
|
||||
handlers = append(handlers, func(r *Request) (*Response, error) {
|
||||
return r.call()
|
||||
})
|
||||
r.Request = r.Request.WithContext(context.WithValue(r.Request.Context(), middlewareKey, &middleware{
|
||||
req: r,
|
||||
handlers: handlers,
|
||||
index: -1,
|
||||
}))
|
||||
resp, err = r.Next()
|
||||
} else {
|
||||
resp, err = r.call()
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// prepare build a http request.
|
||||
func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Request, err error) {
|
||||
method = strings.ToUpper(method)
|
||||
url = r.client.baseUrl + url
|
||||
|
||||
var params string
|
||||
if len(data) > 0 {
|
||||
switch data[0].(type) {
|
||||
case string:
|
||||
params = data[0].(string)
|
||||
case []byte:
|
||||
params = string(data[0].([]byte))
|
||||
default:
|
||||
switch r.client.headers[HeaderContentType] {
|
||||
case ContentTypeJson:
|
||||
if b, err := json.Marshal(data[0]); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
params = string(b)
|
||||
}
|
||||
case ContentTypeXml:
|
||||
if b, err := xml.Marshal(data[0]); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
params = string(b)
|
||||
}
|
||||
default:
|
||||
params = internal.BuildParams(data[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if method == MethodGet {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
|
||||
if params != "" {
|
||||
switch r.client.headers[HeaderContentType] {
|
||||
case ContentTypeJson, ContentTypeXml:
|
||||
buffer = bytes.NewBuffer([]byte(params))
|
||||
default:
|
||||
if strings.Contains(url, "?") {
|
||||
url = url + "&" + params
|
||||
} else {
|
||||
url = url + "?" + params
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if req, err = http.NewRequest(method, url, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(params, fileUploadingKey) {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
writer = multipart.NewWriter(buffer)
|
||||
)
|
||||
|
||||
for _, item := range strings.Split(params, "&") {
|
||||
array := strings.Split(item, "=")
|
||||
if len(array[1]) > 6 && strings.Compare(array[1][0:6], fileUploadingKey) == 0 {
|
||||
path := array[1][6:]
|
||||
if !internal.Exists(path) {
|
||||
return nil, errors.New(fmt.Sprintf(`"%s" does not exist`, path))
|
||||
}
|
||||
if file, err := writer.CreateFormFile(array[0], filepath.Base(path)); err == nil {
|
||||
if f, err := os.Open(path); err == nil {
|
||||
if _, err = io.Copy(file, f); err != nil {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Printf(`%+v`, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Printf(`%+v`, err)
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err = writer.WriteField(array[0], array[1]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req, err = http.NewRequest(method, url, buffer); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
req.Header.Set(HeaderContentType, writer.FormDataContentType())
|
||||
}
|
||||
} else {
|
||||
paramBytes := []byte(params)
|
||||
if req, err = http.NewRequest(method, url, bytes.NewReader(paramBytes)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if v, ok := r.client.headers[HeaderContentType]; ok {
|
||||
req.Header.Set(HeaderContentType, v)
|
||||
} else if len(paramBytes) > 0 {
|
||||
if (paramBytes[0] == '[' || paramBytes[0] == '{') && json.Valid(paramBytes) {
|
||||
req.Header.Set(HeaderContentType, ContentTypeJson)
|
||||
} else if matched, _ := regexp.Match(`^[\w\[\]]+=.+`, paramBytes); matched {
|
||||
req.Header.Set(HeaderContentType, ContentTypeFormUrlEncoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.client.ctx != nil {
|
||||
req = req.WithContext(r.client.ctx)
|
||||
} else {
|
||||
req = req.WithContext(context.Background())
|
||||
}
|
||||
|
||||
if len(r.client.headers) > 0 {
|
||||
for key, value := range r.client.headers {
|
||||
if key != "" {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.client.cookies) > 0 {
|
||||
var cookies = make([]string, 0)
|
||||
for key, value := range r.client.cookies {
|
||||
if key != "" {
|
||||
cookies = append(cookies, key+"="+value)
|
||||
}
|
||||
}
|
||||
req.Header.Set(HeaderCookie, strings.Join(cookies, ";"))
|
||||
}
|
||||
|
||||
if host := req.Header.Get(HeaderHost); host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// call nitiate an HTTP request and return the response data.
|
||||
func (r *Request) call() (resp *Response, err error) {
|
||||
resp = &Response{Request: r.Request}
|
||||
|
||||
for {
|
||||
if resp.Response, err = r.client.Do(r.Request); err != nil {
|
||||
if resp.Response != nil {
|
||||
if err := resp.Response.Body.Close(); err != nil {
|
||||
log.Printf(`%+v`, err)
|
||||
}
|
||||
}
|
||||
|
||||
if r.retryCount > 0 {
|
||||
r.retryCount--
|
||||
time.Sleep(r.retryInterval)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
Reference in New Issue
Block a user