package httpSend
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"path"
"strings"
"time"
)
type HttpData struct {
Data map[string][]string
Params map[string][]string
Files []map[string]interface{}
/*
Files []map[string]interface{} 格式
[
{"远程接收名字": {"文件名": *File}},
列:
{"file": map[string]*os.File{"file.doc": file}}}
{"远程接收名字": "文件路径"}
列:
{"file": r"xxx/xxx.doc}}
]
*/
http.Client
Headers map[string]string
}
// SendFile 发送文件
func SendFile(url string, data *HttpData) (resp *http.Response, err error) {
client := dataInit(data)
bodyBuf := &bytes.Buffer{}
bodyWrite := multipart.NewWriter(bodyBuf)
for key, val := range data.Data {
for _, _v := range val {
_ = bodyWrite.WriteField(key, _v)
}
}
for _, val := range data.Files {
for k, v := range val {
switch value := v.(type) {
case string:
file, err := os.Open(value)
baseName := path.Base(value)
if err != nil {
bodyWrite.Close()
return nil, err
}
defer file.Close()
fileWrite, err := bodyWrite.CreateFormFile(k, baseName)
if err != nil {
bodyWrite.Close()
return nil, err
}
_, err = io.Copy(fileWrite, file)
if err != nil {
bodyWrite.Close()
return nil, err
}
case map[string]*os.File:
var closeFlag bool
var er error
for baseName, file := range value {
if !closeFlag {
fileWrite, err := bodyWrite.CreateFormFile(k, baseName)
if err != nil {
er = err
closeFlag = true
}
_, err = io.Copy(fileWrite, file)
if err != nil {
er = err
closeFlag = true
}
file.Close()
}
}
if closeFlag {
bodyWrite.Close()
return nil, er
}
default:
bodyWrite.Close()
return nil, nil
}
}
}
bodyWrite.Close() //要关闭,会将w.w.boundary刷写到w.writer中
// 创建请求
contentType := bodyWrite.FormDataContentType()
if data.Headers == nil {
data.Headers = map[string]string{
"Content-Type": contentType,
}
}else {
data.Headers["Content-Type"] = contentType
}
return _Send(client, &url, http.MethodPost, bodyBuf, data)
}
// Get 请求
func Get(url string, data *HttpData) (resp *http.Response, err error) {
client := dataInit(data)
url = pUrl(url, data)
return _Send(client, &url, http.MethodGet, nil, data)
}
// Post 请求
func Post(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodPost, data)
}
// Put 请求
func Put(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodPut, data)
}
// Head 请求
func Head(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodHead, data)
}
// Patch 请求
func Patch(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodPatch, data)
}
// Delete 请求
func Delete(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodDelete, data)
}
// Options 请求
func Options(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodOptions, data)
}
// Trace 请求
func Trace(url string, data *HttpData) (resp *http.Response, err error) {
return requests(url, http.MethodTrace, data)
}
func dataInit(data *HttpData) *http.Client {
if data.Timeout == 0 {
data.Timeout = time.Second * 20
}
return &http.Client{Timeout: data.Timeout}
}
// UrlEncode url编码
func UrlEncode(params map[string][]string) (s string) {
param := url.URL{}
q := param.Query()
for k, v := range params {
for _, _v := range v {
q.Add(k, _v)
}
}
s = q.Encode()
return
}
// UrlDecode url解码
func UrlDecode(s string) (mp map[string][]string) {
strSplit := strings.Split(s, "?")
if len(strSplit) == 1 {
return nil
} else if len(strSplit) == 2 && strSplit[1] == "" {
return nil
}
var err error
mp, err = url.ParseQuery(strings.Join(strSplit[1:], "?"))
if err != nil {
return nil
}
return
}
func SetHeaders(req *http.Request, h map[string]string) {
for header, value := range h {
req.Header.Set(header, value)
}
}
func ParserBody(r *http.Response) ([]byte, error) {
if r == nil {
return nil, nil
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
return body, nil
}
// makeUrlParse url 组装
func makeUrlParse(url string, data *HttpData) string {
for k, v := range data.Headers {
data.Headers[strings.Title(k)] = v
}
contentType, ok := data.Headers["Content-Type"]
if !ok {
contentType = "application/x-www-form-urlencoded; charset=UTF-8"
if data.Headers == nil {
data.Headers = make(map[string]string, 1)
}
data.Headers["Content-Type"] = contentType
}
url = pUrl(url, data)
return url
}
// url拼装
func pUrl(url string, data *HttpData) string {
if data.Params != nil {
oldParam := UrlDecode(url)
if oldParam != nil {
// 处理原url 里面的值
for k, v := range oldParam {
_, ok := data.Params[k]
if ok {
data.Params[k] = append(data.Params[k], v...)
} else {
data.Params[k] = v
}
}
url = strings.Split(url, "?")[0]
}
param := UrlEncode(data.Params)
if strings.Index(url, "?") == -1 {
url += "?" + param
} else {
url = strings.Trim(url, "&")
url += "&" + param
}
}
return url
}
func _Send(client *http.Client, url *string, method string, body io.Reader, data *HttpData) (resp *http.Response, err error) {
req, err := http.NewRequest(method, *url, body)
if err != nil {
return nil, err
}
SetHeaders(req, data.Headers)
return client.Do(req)
}
func requests(url string, method string, data *HttpData)(*http.Response, error){
url = makeUrlParse(url, data)
client := dataInit(data)
if strings.Contains(data.Headers["Content-Type"], "application/json") {
reqBody := new(bytes.Buffer)
json.NewEncoder(reqBody).Encode(data.Data)
return _Send(client, &url, method, reqBody, data)
} else {
return _Send(client, &url, method, strings.NewReader(UrlEncode(data.Data)), data)
}
}