You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
simpleRequest/simpleRequest.go

358 lines
9.6 KiB
Go

3 years ago
/*
2 years ago
*FileName: simpleRequest.go
*Author: JJXu
*CreateTime: 2022/3/2 12:33
*Description:
3 years ago
*/
package simpleRequest
import (
"bytes"
3 years ago
"crypto/tls"
"errors"
3 years ago
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
func NewRequest(opts ...OPTION) *SimpleRequest {
3 years ago
var (
hd = http.Header{}
qp = url.Values{}
)
var r = &SimpleRequest{
3 years ago
//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,
3 years ago
}
if len(opts) > 0 {
for _, o := range opts {
r = o(r)
}
}
return r
3 years ago
}
type SimpleRequest struct {
url string
queryParams url.Values
body io.Reader
headers http.Header
omitHeaderKeys []string
transport *http.Transport
3 years ago
BodyEntryMark EntryMark // 用于标记输入的body内容格式
BodyEntries map[string]any // 输入的body中的内容
bodyEntryParsers map[string]IBodyEntryParser // 用于将BodyEntries中的内容解析后传入request body中
disableDefaultContentType bool // 禁用默认的ContentType
disableCopyRequestBody bool // 禁用默认的ContentType在进行http请求后SimpleRequest.Request.Body中内容会无法读取
timeout time.Duration
3 years ago
Response *http.Response //用于获取完整的返回内容。请注意要在请求之后才能获取
Request *http.Request //用于获取完整的请求内容。请注意要在请求之后才能获取
3 years ago
//cookies map[string]string
//data any
3 years ago
//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),
// }
//}
3 years ago
//------------------------------------------------------
//
// 数据准备
2 years ago
// Authorization 添加令牌的方法集合
func (s *SimpleRequest) Authorization() *Authorization {
return &Authorization{
simpleReq: s,
}
}
2 years ago
// Headers 添加请求头
3 years ago
func (s *SimpleRequest) Headers() *HeadersConf {
return &HeadersConf{
simpleReq: s,
}
}
2 years ago
// Body 添加请求体
3 years ago
func (s *SimpleRequest) Body() *BodyConf {
return &BodyConf{
simpleReq: s,
}
}
2 years ago
// QueryParams 添加url后面的参数
3 years ago
func (s *SimpleRequest) QueryParams() *QueryParams {
return &QueryParams{
simpleReq: s,
}
}
2 years ago
// 跳过证书验证
3 years ago
func (s *SimpleRequest) SkipCertVerify() *SimpleRequest {
s.transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return s
}
2 years ago
// 设置超时时间
3 years ago
func (s *SimpleRequest) TimeOut(t time.Duration) *SimpleRequest {
s.timeout = t
return s
}
2 years ago
// ------------------------------------------------------
3 years ago
//
2 years ago
// 发送请求
3 years ago
//
2 years ago
// 发送postt请求
3 years ago
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 {
err = errors.New("[client.Do Err]:" + err.Error())
return
}
//v0.0.2更新将request和response内容返回便于用户进行分析 JJXu 03-11-2022
s.Request = request
if resp != nil {
s.Response = resp
defer resp.Body.Close()
body, err = io.ReadAll(resp.Body)
3 years ago
}
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)
3 years ago
}
// 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)
3 years ago
}
2 years ago
// 通用的请求方法
func (s *SimpleRequest) LaunchTo(urls, method string) (body []byte, err error) {
// body
s.initBody()
var r *http.Request
copBody, err := io.ReadAll(s.body)
if err != nil {
return
}
if !s.disableCopyRequestBody {
// 使r.body在请求后仍旧可读,便于使用者对请求过程进行分析
r, err = http.NewRequest(method, urls, io.NopCloser(bytes.NewBuffer(copBody)))
if err != nil {
return nil, err
}
defer func() {
r.Body = io.NopCloser(bytes.NewBuffer(copBody))
}()
} else {
r, err = http.NewRequest(method, urls, s.body)
if err != nil {
return nil, err
}
}
//headers
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{}
1 year ago
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)
}
2 years ago
// ------------------------------------------------------
3 years ago
//
// Automatically parses the request body based on the content-type type defined in the request header
3 years ago
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 {
s.body = GetStringEntryTypeBody(s.BodyEntries)
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 {
s.body = GetStringEntryTypeBody(s.BodyEntries)
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 {
for k, v := range s.BodyEntries {
if v == nil {
break
}
switch k {
case StringEntryType.string():
s.body = GetStringEntryTypeBody(s.BodyEntries)
break
case BytesEntryType.string():
s.body = GetBytesEntryTypeBody(s.BodyEntries)
break
default:
tmpData := url.Values{}
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)
default:
// 自动处理body数据
s.body = new(CommonParser).Unmarshal(s.BodyEntryMark, s.BodyEntries)
3 years ago
}
} else {
switch s.BodyEntryMark {
case BytesEntryType:
s.body = GetBytesEntryTypeBody(s.BodyEntries)
case StringEntryType:
s.body = GetStringEntryTypeBody(s.BodyEntries)
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())
if !s.disableDefaultContentType {
s.Headers().ConentType_formUrlencoded()
}
return
}
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
3 years ago
}
3 years ago
}
3 years ago
}