dongfeng-pay/gateway/utils/http.go

309 lines
6.1 KiB
Go

package utils
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
// Request HTTP request
type Request struct {
customRequest func(req *http.Request, data *bytes.Buffer) // 用于定义HEADER, 如添加sign等
url string
params map[string]interface{} // URL后的参数
body string // Body数据
bodyJSON interface{} // 可JSON Marshal 的Body的数据
timeout time.Duration // Client timeout
headers map[string]string
request *http.Request
response *Response
method string
err error
}
// Response HTTP response
type Response struct {
*http.Response
err error
}
// ==================================== Request ====================================
// Reset set all fields to default value, use at pool
func (req *Request) Reset() {
req.params = nil
req.body = ""
req.bodyJSON = nil
req.timeout = 0
req.headers = nil
req.request = nil
req.response = nil
req.method = ""
req.err = nil
}
// SetURL 设置URL
func (req *Request) SetURL(path string) *Request {
req.url = path
return req
}
// SetParams 设置URL后的参数
func (req *Request) SetParams(params map[string]interface{}) *Request {
if req.params == nil {
req.params = params
} else {
for k, v := range params {
req.params[k] = v
}
}
return req
}
// SetParam 设置URL后的参数
func (req *Request) SetParam(k string, v interface{}) *Request {
if req.params == nil {
req.params = make(map[string]interface{})
}
req.params[k] = v
return req
}
// SetBody 设置Body数据
func (req *Request) SetBody(body string) *Request {
req.body = body
return req
}
// SetJSONBody 设置Body数据, JSON格式
func (req *Request) SetJSONBody(body interface{}) *Request {
req.bodyJSON = body
return req
}
// SetTimeout 超时时间
func (req *Request) SetTimeout(t time.Duration) *Request {
req.timeout = t
return req
}
// SetContentType 设置ContentType
func (req *Request) SetContentType(a string) *Request {
req.SetHeader("Content-Type", a)
return req
}
// SetHeader 设置Request Header 的值
func (req *Request) SetHeader(k, v string) *Request {
if req.headers == nil {
req.headers = make(map[string]string)
}
req.headers[k] = v
return req
}
// CustomRequest 自定义Request
// 如添加sign, 设置header等
func (req *Request) CustomRequest(f func(req *http.Request, data *bytes.Buffer)) *Request {
req.customRequest = f
return req
}
// GET 发送GET请求
func (req *Request) GET() (*Response, error) {
req.method = "GET"
return req.pull()
}
// DELETE 发送DELETE请求
func (req *Request) DELETE() (*Response, error) {
req.method = "DELETE"
return req.pull()
}
// POST 发送POST请求
func (req *Request) POST() (*Response, error) {
req.method = "POST"
return req.push()
}
// PUT 发送PUT请求
func (req *Request) PUT() (*Response, error) {
req.method = "PUT"
return req.push()
}
// PATCH 发送PATCH请求
func (req *Request) PATCH() (*Response, error) {
req.method = "PATCH"
return req.push()
}
// Do a request
func (req *Request) Do(method string, data interface{}) (*Response, error) {
req.method = method
switch method {
case "GET", "DELETE":
if data != nil {
if params, ok := data.(map[string]interface{}); ok {
req.SetParams(params)
} else {
req.err = errors.New("params is not a map[string]interface{}")
return nil, req.err
}
}
return req.pull()
case "POST", "PUT", "PATCH":
if data != nil {
req.SetJSONBody(data)
}
return req.push()
}
req.err = errors.New("unknow method " + method)
return nil, req.err
}
func (req *Request) pull() (*Response, error) {
val := ""
if len(req.params) > 0 {
values := url.Values{}
for k, v := range req.params {
values.Add(k, fmt.Sprintf("%v", v))
}
val += values.Encode()
}
if val != "" {
if strings.Contains(req.url, "?") {
req.url += "&" + val
} else {
req.url += "?" + val
}
}
var buf *bytes.Buffer
if req.customRequest != nil {
buf = bytes.NewBufferString(val)
}
return req.send(nil, buf)
}
func (req *Request) push() (*Response, error) {
var buf = new(bytes.Buffer)
if req.bodyJSON != nil {
body, err := json.Marshal(req.bodyJSON)
if err != nil {
req.err = err
return nil, req.err
}
buf = bytes.NewBuffer(body)
} else {
buf = bytes.NewBufferString(req.body)
}
return req.send(buf, buf)
}
func (req *Request) send(body io.Reader, buf *bytes.Buffer) (*Response, error) {
req.request, req.err = http.NewRequest(req.method, req.url, body)
if req.err != nil {
return nil, req.err
}
if req.customRequest != nil {
req.customRequest(req.request, buf)
}
if req.headers != nil {
for k, v := range req.headers {
req.request.Header.Add(k, v)
}
}
if req.timeout < 1 {
req.timeout = 1 * time.Minute
}
client := http.Client{Timeout: req.timeout}
resp := new(Response)
resp.Response, resp.err = client.Do(req.request)
req.response = resp
req.err = resp.err
return resp, resp.err
}
// Response return response
func (req *Request) Response() (*Response, error) {
if req.err != nil {
return nil, req.err
}
return req.response, req.response.Error()
}
// ==================================== Response ====================================
// Error return err
func (resp *Response) Error() error {
return resp.err
}
// BodyString 返回HttpResponse的body数据
func (resp *Response) BodyString() (string, error) {
if resp.err != nil {
return "", resp.err
}
body, err := resp.ReadBody()
return string(body), err
}
// ReadBody 返回HttpResponse的body数据
func (resp *Response) ReadBody() ([]byte, error) {
if resp.err != nil {
return []byte{}, resp.err
}
if resp.Response == nil {
return []byte{}, errors.New("nil")
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, err
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))
return body, nil
}
// BindJSON parses the response's body as JSON
func (resp *Response) BindJSON(v interface{}) error {
if resp.err != nil {
return resp.err
}
body, err := resp.ReadBody()
if err != nil {
return err
}
return json.Unmarshal(body, v)
}