@@ -0,0 +1,195 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
client = http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConnsPerHost: 5,
|
||||
MaxConnsPerHost: 100,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type ByteSize int64
|
||||
|
||||
const (
|
||||
_ = iota // ignore first value by assigning to blank identifier
|
||||
KB ByteSize = 1 << (10 * iota)
|
||||
MB
|
||||
)
|
||||
|
||||
var (
|
||||
outOfBodySizeErr = errors.New("out of body size limit")
|
||||
)
|
||||
|
||||
type ResponseBody struct {
|
||||
StatusCode int
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type RequestFormData map[string]string
|
||||
|
||||
// Post
|
||||
// Note: 只会读取小于1M的数据
|
||||
func Post(url string, header map[string]string, body io.Reader) (fr *ResponseBody, err error) {
|
||||
fr, err = do(http.MethodPost, url, header, body, int64(1024*MB))
|
||||
return
|
||||
}
|
||||
|
||||
// PostFormData 提交标准的form表单
|
||||
func PostFormData(url string, fromdata RequestFormData) (fr *ResponseBody, err error) {
|
||||
var b bytes.Buffer
|
||||
writer := multipart.NewWriter(&b)
|
||||
|
||||
for k, v := range fromdata {
|
||||
if err = writer.WriteField(k, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = writer.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
header := map[string]string{"Content-Type": writer.FormDataContentType()}
|
||||
fr, err = do(http.MethodPost, url, header, &b, 2*int64(KB))
|
||||
return
|
||||
}
|
||||
|
||||
// Get
|
||||
// Note: 只会读取小于1M的数据
|
||||
func Get(url string, header map[string]string) (fr *ResponseBody, err error) {
|
||||
fr, err = do(http.MethodGet, url, header, nil, int64(KB))
|
||||
return
|
||||
}
|
||||
|
||||
func GetWithBody(url string, header map[string]string, body io.Reader) (fr *ResponseBody, err error) {
|
||||
fr, err = do(http.MethodGet, url, header, body, int64(20*MB))
|
||||
return
|
||||
}
|
||||
|
||||
// GetLargeFile 获取大文件。2M
|
||||
func GetLargeFile(url string, header map[string]string) (fr *ResponseBody, err error) {
|
||||
fr, err = do(http.MethodGet, url, header, nil, int64(20*MB))
|
||||
return
|
||||
}
|
||||
|
||||
func do(method string, url string, header map[string]string, body io.Reader, size int64) (fr *ResponseBody, err error) {
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for k, v := range header {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.ContentLength > size {
|
||||
err = outOfBodySizeErr
|
||||
return
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(io.LimitReader(resp.Body, size))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fr = &ResponseBody{
|
||||
StatusCode: resp.StatusCode,
|
||||
Data: data,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 推送对象到文件服务器
|
||||
func PostObject(ctx context.Context, url string, header map[string]string, body []byte, objName string) (string, error) {
|
||||
base64data := base64.StdEncoding.EncodeToString(body)
|
||||
|
||||
req := struct {
|
||||
Name string `json:"fileName"`
|
||||
Data string `json:"fileData"`
|
||||
}{
|
||||
Name: objName,
|
||||
Data: base64data,
|
||||
}
|
||||
|
||||
jsonBytes, _ := json.Marshal(req)
|
||||
|
||||
resp, err := Post(url, header, bytes.NewReader(jsonBytes))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
type Obj struct {
|
||||
Domain string `json:"domain"`
|
||||
Name string `json:"fileName"`
|
||||
}
|
||||
|
||||
fsResp := struct {
|
||||
Code int `json:"code"`
|
||||
Object Obj `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}{}
|
||||
|
||||
if err = json.Unmarshal(resp.Data, &fsResp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if fsResp.Code != 200 || fsResp.Object.Name == "" {
|
||||
return "", fmt.Errorf("上传fs失败")
|
||||
}
|
||||
|
||||
return fsResp.Object.Name, nil
|
||||
}
|
||||
|
||||
func PostWithBind(ctx context.Context, bind interface{}, url string, body io.Reader) error {
|
||||
if err := verifyBind(bind); err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("response status code:%d", resp.StatusCode)
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, bind)
|
||||
}
|
||||
|
||||
func verifyBind(bind interface{}) error {
|
||||
bType := reflect.TypeOf(bind)
|
||||
if bType.Kind() != reflect.Ptr {
|
||||
return errors.New("bind must be a Ptr")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package http
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleGet() {
|
||||
urlstr := "https://palce.hzbeisheng.com/api/sms"
|
||||
data, err := Get(urlstr, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data.Data))
|
||||
|
||||
// Output:
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user