341 lines
8.8 KiB
Go
341 lines
8.8 KiB
Go
/*
|
||
*FileName: simpleRequest.go
|
||
*Author: JJXu
|
||
*CreateTime: 2022/3/2 上午12:33
|
||
*Description:
|
||
*/
|
||
|
||
package simpleRequest
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/tls"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"net/url"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
func NewRequest(opts ...OPTION) *SimpleRequest {
|
||
var (
|
||
hd = http.Header{}
|
||
qp = url.Values{}
|
||
)
|
||
|
||
var r = &SimpleRequest{
|
||
//headers: make(map[string]string),
|
||
//cookies: make(map[string]string),
|
||
timeout: time.Second * 7,
|
||
queryParams: qp,
|
||
headers: hd,
|
||
BodyEntries: make(map[string]any),
|
||
bodyEntryParsers: bodyEntryParsers,
|
||
}
|
||
if len(opts) > 0 {
|
||
for _, o := range opts {
|
||
r = o(r)
|
||
}
|
||
}
|
||
return r
|
||
}
|
||
|
||
type SimpleRequest struct {
|
||
url string
|
||
queryParams url.Values
|
||
body io.Reader
|
||
headers http.Header
|
||
omitHeaderKeys []string
|
||
transport *http.Transport
|
||
|
||
BodyEntryMark EntryMark
|
||
BodyEntries map[string]any
|
||
bodyEntryParsers map[string]IBodyEntryParser
|
||
|
||
timeout time.Duration
|
||
|
||
Response http.Response //用于获取完整的返回内容。请注意要在请求之后才能获取
|
||
Request http.Request //用于获取完整的请求内容。请注意要在请求之后才能获取
|
||
//cookies map[string]string
|
||
//data any
|
||
//cli *http.Client
|
||
//debug bool
|
||
//method string
|
||
//time int64
|
||
//disableKeepAlives bool
|
||
//tlsClientConfig *tls.Config
|
||
//jar http.CookieJar
|
||
//proxy func(*http.Request) (*url.URL, error)
|
||
//checkRedirect func(req *http.Request, via []*http.Request) error
|
||
}
|
||
|
||
//func (s *SimpleRequest) NewRequest() *SimpleRequest {
|
||
// var qp = url.Values{}
|
||
// return &SimpleRequest{
|
||
// //headers: make(map[string]string),
|
||
// //cookies: make(map[string]string),
|
||
// timeout: time.Second * 7,
|
||
// queryParams: qp,
|
||
// BodyEntries: make(map[string]any),
|
||
// }
|
||
//}
|
||
|
||
//------------------------------------------------------
|
||
//
|
||
// 数据准备
|
||
|
||
// Authorization 添加令牌的方法集合
|
||
func (s *SimpleRequest) Authorization() *Authorization {
|
||
return &Authorization{
|
||
simpleReq: s,
|
||
}
|
||
}
|
||
|
||
// Headers 添加请求头
|
||
func (s *SimpleRequest) Headers() *HeadersConf {
|
||
return &HeadersConf{
|
||
simpleReq: s,
|
||
}
|
||
}
|
||
|
||
// Body 添加请求体
|
||
func (s *SimpleRequest) Body() *BodyConf {
|
||
return &BodyConf{
|
||
simpleReq: s,
|
||
}
|
||
}
|
||
|
||
// QueryParams 添加url后面的参数
|
||
func (s *SimpleRequest) QueryParams() *QueryParams {
|
||
return &QueryParams{
|
||
simpleReq: s,
|
||
}
|
||
}
|
||
|
||
// 跳过证书验证
|
||
func (s *SimpleRequest) SkipCertVerify() *SimpleRequest {
|
||
|
||
s.transport = &http.Transport{
|
||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||
}
|
||
return s
|
||
}
|
||
|
||
// 设置超时时间
|
||
func (s *SimpleRequest) TimeOut(t time.Duration) *SimpleRequest {
|
||
s.timeout = t
|
||
return s
|
||
}
|
||
|
||
// ------------------------------------------------------
|
||
//
|
||
// 发送请求
|
||
//
|
||
// 发送postt请求
|
||
func (s *SimpleRequest) do(request *http.Request) (body []byte, err error) {
|
||
//3. 建立http客户端
|
||
client := &http.Client{
|
||
Timeout: s.timeout,
|
||
}
|
||
if s.transport != nil {
|
||
client.Transport = s.transport
|
||
}
|
||
//3.1 发送数据
|
||
resp, err := client.Do(request)
|
||
if err != nil {
|
||
fmt.Println("【Request Error】:", err.Error())
|
||
return
|
||
}
|
||
|
||
//v0.0.2更新,将request和response内容返回,便于用户进行分析 JJXu 03-11-2022
|
||
if resp != nil {
|
||
s.Response = *resp
|
||
} else {
|
||
return
|
||
}
|
||
if request != nil {
|
||
s.Request = *request
|
||
}
|
||
|
||
defer resp.Body.Close()
|
||
//3.2 获取数据
|
||
body, err = io.ReadAll(resp.Body)
|
||
return
|
||
}
|
||
|
||
// POST method does POST HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) POST(urls string) (body []byte, err error) {
|
||
return s.LaunchTo(urls, http.MethodPost)
|
||
}
|
||
|
||
// GET method does GET HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) GET(urls string) (body []byte, err error) {
|
||
return s.LaunchTo(urls, http.MethodGet)
|
||
}
|
||
|
||
// 通用的请求方法
|
||
func (s *SimpleRequest) LaunchTo(urls, method string) (body []byte, err error) {
|
||
// body
|
||
s.initBody()
|
||
r, err := http.NewRequest(method, urls, s.body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//headers
|
||
//for k := range s.headers {
|
||
// r.Header[k] = append(r.Header[k], s.headers[k]...)
|
||
// s.headers.Del(k)
|
||
//}
|
||
r.Header = s.headers
|
||
for _, k := range s.omitHeaderKeys {
|
||
r.Header.Del(k)
|
||
}
|
||
//queryParams
|
||
if r.URL.RawQuery != "" {
|
||
values, err := url.ParseQuery(r.URL.RawQuery)
|
||
if err == nil {
|
||
newValues := url.Values{}
|
||
for k := range values {
|
||
newValues.Set(k, values.Get(k))
|
||
}
|
||
for k := range s.queryParams {
|
||
newValues.Set(k, s.queryParams.Get(k))
|
||
}
|
||
s.queryParams = newValues
|
||
}
|
||
}
|
||
r.URL.RawQuery = s.queryParams.Encode()
|
||
|
||
body, err = s.do(r)
|
||
return
|
||
}
|
||
|
||
// PUT method does PUT HTTP request. It's defined in section 4.3.4 of RFC7231.
|
||
func (s *SimpleRequest) PUT(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodPut)
|
||
}
|
||
|
||
// DELETE method does DELETE HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) DELETE(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodDelete)
|
||
}
|
||
|
||
// Patch method does Patch HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) PATCH(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodPatch)
|
||
}
|
||
|
||
// HEAD method does HEAD HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) HEAD(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodHead)
|
||
}
|
||
|
||
// CONNECT method does CONNECT HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) CONNECT(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodConnect)
|
||
}
|
||
|
||
// OPTIONS method does OPTIONS HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) OPTIONS(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodOptions)
|
||
}
|
||
|
||
// TRACE method does TRACE HTTP request. It's defined in section 2 of RFC5789.
|
||
func (s *SimpleRequest) TRACE(url string) (body []byte, err error) {
|
||
return s.LaunchTo(url, http.MethodTrace)
|
||
}
|
||
|
||
// ------------------------------------------------------
|
||
//
|
||
// 这里数据
|
||
func (s *SimpleRequest) initBody() {
|
||
contentTypeData := s.headers.Get(hdrContentTypeKey)
|
||
if contentTypeData != "" {
|
||
switch {
|
||
case IsJSONType(contentTypeData):
|
||
var parser, ok = s.bodyEntryParsers[jsonContentType]
|
||
if !ok {
|
||
parser = new(JsonParser)
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
|
||
case strings.Contains(contentTypeData, formDataType):
|
||
var parser, ok = s.bodyEntryParsers[formDataType]
|
||
if !ok {
|
||
parser = new(FormDataParser)
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
fdParser := parser.(*FormDataParser)
|
||
s.headers.Set("Content-Type", fdParser.ContentType)
|
||
|
||
case IsXMLType(contentTypeData):
|
||
//application/soap+xml ,application/xml
|
||
var parser, ok = s.bodyEntryParsers[xmlDataType]
|
||
if !ok {
|
||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
||
s.body = strings.NewReader(data)
|
||
return
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
|
||
case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType):
|
||
var parser, ok = s.bodyEntryParsers[textPlainType]
|
||
if !ok {
|
||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
||
s.body = strings.NewReader(data)
|
||
return
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
|
||
case strings.Contains(contentTypeData, "form-urlencoded"):
|
||
//default header type is "x-www-form-urlencoded"
|
||
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
||
if !ok {
|
||
tmpData := url.Values{}
|
||
for k, v := range s.BodyEntries {
|
||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||
}
|
||
s.body = strings.NewReader(tmpData.Encode())
|
||
s.Headers().ConentType_formUrlencoded()
|
||
return
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
default:
|
||
//todo Automatically determine the data type
|
||
tmpData := url.Values{}
|
||
for k, v := range tmpData {
|
||
if strings.HasPrefix(k, FormFilePathKey.string()) {
|
||
k = k[len(FormFilePathKey):]
|
||
}
|
||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||
}
|
||
s.body = strings.NewReader(tmpData.Encode())
|
||
}
|
||
} else {
|
||
switch s.BodyEntryMark {
|
||
case BytesEntryType:
|
||
s.body = bytes.NewReader(s.BodyEntries[BytesEntryType.string()].([]byte))
|
||
case StringEntryType:
|
||
s.body = strings.NewReader(s.BodyEntries[BytesEntryType.string()].(string))
|
||
default:
|
||
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
||
if !ok {
|
||
tmpData := url.Values{}
|
||
for k, v := range s.BodyEntries {
|
||
if strings.HasPrefix(k, FormFilePathKey.string()) {
|
||
k = k[len(FormFilePathKey):]
|
||
}
|
||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||
}
|
||
s.body = strings.NewReader(tmpData.Encode())
|
||
s.Headers().ConentType_formUrlencoded()
|
||
return
|
||
}
|
||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||
}
|
||
|
||
}
|
||
|
||
}
|