Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
730e3462f6 | ||
|
|
ae3982faaa | ||
|
|
166fe96265 | ||
|
|
8a0a21fc5e | ||
|
|
025f911c0e | ||
|
|
21a167304b | ||
|
|
54b481c9f5 | ||
|
|
408995f2b4 | ||
|
|
4b77382218 | ||
|
|
13dfdee51c | ||
|
|
01df404ead | ||
|
|
8383a3820f | ||
|
|
3ee03a1c7b |
35
base.go
35
base.go
@@ -7,33 +7,46 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func buildBodyRequest(ver, rawurl string, body *Body) *http.Request {
|
||||
func buildBodyRequest(wf *Workflow) *http.Request {
|
||||
var req *http.Request
|
||||
var err error
|
||||
contentType := ""
|
||||
|
||||
if body.IOBody == nil {
|
||||
req, err = http.NewRequest(ver, rawurl, nil)
|
||||
if wf.Body.IOBody == nil {
|
||||
req, err = http.NewRequest(wf.Method, wf.GetStringURL(), nil)
|
||||
} else {
|
||||
var bodybuf *bytes.Buffer
|
||||
switch body.IOBody.(type) {
|
||||
switch wf.Body.IOBody.(type) {
|
||||
case []byte:
|
||||
bodybuf = bytes.NewBuffer(body.IOBody.([]byte))
|
||||
bodybuf = bytes.NewBuffer(wf.Body.IOBody.([]byte))
|
||||
case *bytes.Buffer:
|
||||
bodybuf = bytes.NewBuffer(body.IOBody.(*bytes.Buffer).Bytes())
|
||||
bodybuf = bytes.NewBuffer(wf.Body.IOBody.(*bytes.Buffer).Bytes())
|
||||
default:
|
||||
panic(errors.New("the type is not exist, type is" + reflect.TypeOf(body.IOBody).String()))
|
||||
panic(errors.New("the type is not exist, type is" + reflect.TypeOf(wf.Body.IOBody).String()))
|
||||
}
|
||||
req, err = http.NewRequest(ver, rawurl, bodybuf)
|
||||
req, err = http.NewRequest(wf.Method, wf.GetStringURL(), bodybuf)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if body.ContentType == "" {
|
||||
req.Header.Set(HeaderKeyContentType, TypeURLENCODED)
|
||||
if wf.Body.ContentType != "" {
|
||||
if wf.Body.ContentType == TypeContentEmpty {
|
||||
contentType = ""
|
||||
} else {
|
||||
req.Header.Set(HeaderKeyContentType, body.ContentType)
|
||||
contentType = wf.Body.ContentType
|
||||
}
|
||||
} else {
|
||||
if contentType == "" {
|
||||
if wf.Method == "POST" || wf.Method == "PUT" || wf.Method == "PATCH" {
|
||||
contentType = TypeURLENCODED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
req.Header.Set(HeaderKeyContentType, contentType)
|
||||
}
|
||||
|
||||
return req
|
||||
|
||||
85
session.go
85
session.go
@@ -7,6 +7,7 @@ import (
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/publicsuffix"
|
||||
@@ -33,9 +34,11 @@ type Session struct {
|
||||
client *http.Client
|
||||
transport *http.Transport
|
||||
cookiejar http.CookieJar
|
||||
params *Body
|
||||
Header http.Header
|
||||
body *Body
|
||||
auth *BasicAuth
|
||||
|
||||
Header http.Header
|
||||
Query url.Values
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -45,6 +48,10 @@ const (
|
||||
TypeXML = "text/xml"
|
||||
// TypeURLENCODED 类型
|
||||
TypeURLENCODED = "application/x-www-form-urlencoded"
|
||||
// TypeForm PostForm类型
|
||||
TypeForm = TypeURLENCODED
|
||||
// TypeContentEmpty 没有Form的类型 Content
|
||||
TypeContentEmpty = "ContentEmpty"
|
||||
// TypeFormData 类型
|
||||
TypeFormData = "multipart/form-data"
|
||||
// HeaderKeyHost Host
|
||||
@@ -94,7 +101,7 @@ func NewSession() *Session {
|
||||
}
|
||||
|
||||
client.Jar = cjar
|
||||
return &Session{client: client, params: &Body{}, transport: transport, auth: nil, cookiejar: client.Jar, Header: make(http.Header)}
|
||||
return &Session{client: client, body: &Body{}, transport: transport, auth: nil, cookiejar: client.Jar, Header: make(http.Header)}
|
||||
}
|
||||
|
||||
// SetConfig 设置配置
|
||||
@@ -121,15 +128,11 @@ func (ses *Session) SetConfig(typeConfig TypeConfig, values interface{}) {
|
||||
case ConfigCookiejar:
|
||||
v := values.(bool)
|
||||
if v {
|
||||
if ses.cookiejar == nil {
|
||||
j, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ses.cookiejar = j
|
||||
if ses.client.Jar == nil {
|
||||
ses.client.Jar = ses.cookiejar
|
||||
}
|
||||
} else {
|
||||
ses.cookiejar = nil
|
||||
ses.client.Jar = nil
|
||||
}
|
||||
case ConfigProxy:
|
||||
switch v := values.(type) {
|
||||
@@ -170,6 +173,26 @@ func (ses *Session) SetConfig(typeConfig TypeConfig, values interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
// SetQuery 设置url query的持久参数的值
|
||||
func (ses *Session) SetQuery(values url.Values) {
|
||||
ses.Query = values
|
||||
}
|
||||
|
||||
// GetQuery 获取get query的值
|
||||
func (ses *Session) GetQuery() url.Values {
|
||||
return ses.Query
|
||||
}
|
||||
|
||||
// SetHeader 设置set Header的值
|
||||
func (ses *Session) SetHeader(header http.Header) {
|
||||
ses.Header = header
|
||||
}
|
||||
|
||||
// GetHeader 获取get Header的值
|
||||
func (ses *Session) GetHeader() http.Header {
|
||||
return ses.Header
|
||||
}
|
||||
|
||||
// SetCookies 设置Cookies 或者添加Cookies Del
|
||||
func (ses *Session) SetCookies(u *url.URL, cookies []*http.Cookie) {
|
||||
ses.cookiejar.SetCookies(u, cookies)
|
||||
@@ -177,6 +200,7 @@ func (ses *Session) SetCookies(u *url.URL, cookies []*http.Cookie) {
|
||||
|
||||
// Cookies 返回 Cookies
|
||||
func (ses *Session) Cookies(u *url.URL) []*http.Cookie {
|
||||
|
||||
return ses.cookiejar.Cookies(u)
|
||||
}
|
||||
|
||||
@@ -191,59 +215,62 @@ func (ses *Session) DelCookies(u *url.URL, name string) {
|
||||
ses.SetCookies(u, cookies)
|
||||
}
|
||||
|
||||
// ClearCookies 清楚所有cookiejar上的cookies
|
||||
func (ses *Session) ClearCookies() {
|
||||
cjar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ses.cookiejar = cjar
|
||||
ses.client.Jar = ses.cookiejar
|
||||
}
|
||||
|
||||
// Get 请求
|
||||
func (ses *Session) Get(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "GET"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Post 请求
|
||||
func (ses *Session) Post(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "POST"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Put 请求
|
||||
func (ses *Session) Put(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "PUT"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Patch 请求
|
||||
func (ses *Session) Patch(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "PATCH"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Delete 请求
|
||||
func (ses *Session) Delete(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "DELETE"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Head 请求
|
||||
func (ses *Session) Head(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "HEAD"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
// Options 请求
|
||||
func (ses *Session) Options(url string) *Workflow {
|
||||
wf := NewWorkflow(ses)
|
||||
wf := NewWorkflow(ses, url)
|
||||
wf.Method = "OPTIONS"
|
||||
wf.SetURL(url)
|
||||
return wf
|
||||
}
|
||||
|
||||
@@ -252,3 +279,13 @@ func (ses *Session) Options(url string) *Workflow {
|
||||
func (ses *Session) CloseIdleConnections() {
|
||||
ses.client.Transport.(*http.Transport).CloseIdleConnections()
|
||||
}
|
||||
|
||||
// EnsureTransporterFinalized will ensure that when the HTTP client is GCed
|
||||
// the runtime will close the idle connections (so that they won't leak)
|
||||
// this function was adopted from Hashicorp's go-cleanhttp package
|
||||
// 暂时不用, 标记到以后是否起作用
|
||||
func EnsureTransporterFinalized(httpTransport *http.Transport) {
|
||||
runtime.SetFinalizer(&httpTransport, func(transportInt **http.Transport) {
|
||||
(*transportInt).CloseIdleConnections()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ func TestSession_Get(t *testing.T) {
|
||||
fields fields
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "Get test",
|
||||
fields: fields{client: &http.Client{}},
|
||||
@@ -107,7 +106,6 @@ func TestSession_Setparams(t *testing.T) {
|
||||
want *regexp.Regexp
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "test Setparams",
|
||||
args: args{params: []interface{}{map[string]string{"a": "1", "b": "2"}}},
|
||||
@@ -285,7 +283,6 @@ func TestSession_SetConfig(t *testing.T) {
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "test timeout",
|
||||
args: args{typeConfig: ConfigRequestTimeout, values: 0.01},
|
||||
@@ -343,6 +340,8 @@ func TestSession_SetConfigInsecure(t *testing.T) {
|
||||
func TestSession_Cookies(t *testing.T) {
|
||||
ses := NewSession()
|
||||
|
||||
t.Run("set cookie", func(t *testing.T) {
|
||||
|
||||
resp, err := ses.Get("http://httpbin.org/cookies/set").AddKVCookie("a", "1").Execute()
|
||||
if err != nil {
|
||||
t.Error("cookies set error", err)
|
||||
@@ -351,12 +350,15 @@ func TestSession_Cookies(t *testing.T) {
|
||||
if !regexp.MustCompile(`"a": "1"`).MatchString(resp.DContent) {
|
||||
t.Error(resp.DContent)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSession_Header(t *testing.T) {
|
||||
chromeua := "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
|
||||
ses := NewSession()
|
||||
|
||||
t.Run("ua header test", func(t *testing.T) {
|
||||
|
||||
ses.Header.Add(HeaderKeyUA, chromeua)
|
||||
resp, err := ses.Get("https://www.baidu.com").Execute()
|
||||
if err != nil {
|
||||
@@ -376,4 +378,5 @@ func TestSession_Header(t *testing.T) {
|
||||
if len(resp.DContent) <= 5000 {
|
||||
t.Error(resp.DContent, len(resp.DContent))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
86
workflow.go
86
workflow.go
@@ -1,9 +1,11 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Workflow 工作流
|
||||
@@ -17,10 +19,12 @@ type Workflow struct {
|
||||
}
|
||||
|
||||
// NewWorkflow new and init workflow
|
||||
func NewWorkflow(ses *Session) *Workflow {
|
||||
func NewWorkflow(ses *Session, u string) *Workflow {
|
||||
wf := &Workflow{}
|
||||
wf.SwitchSession(ses)
|
||||
|
||||
wf.SetURL(u)
|
||||
|
||||
wf.Body = &Body{}
|
||||
wf.Header = make(http.Header)
|
||||
wf.Cookies = make(map[string]*http.Cookie)
|
||||
@@ -44,6 +48,16 @@ func (wf *Workflow) SetHeader(key, value string) *Workflow {
|
||||
return wf
|
||||
}
|
||||
|
||||
// GetHeader 获取Workflow Header
|
||||
func (wf *Workflow) GetHeader() http.Header {
|
||||
return wf.Header
|
||||
}
|
||||
|
||||
// GetCombineHeader 获取后的Header信息
|
||||
func (wf *Workflow) GetCombineHeader() http.Header {
|
||||
return mergeMapList(wf.session.Header, wf.Header)
|
||||
}
|
||||
|
||||
// DelHeader 添加头信息 Get方法从Header参数上获取
|
||||
func (wf *Workflow) DelHeader(key string) *Workflow {
|
||||
wf.Header.Del(key)
|
||||
@@ -83,7 +97,8 @@ func (wf *Workflow) DelCookie(name interface{}) *Workflow {
|
||||
|
||||
// GetStringURL 获取url的string形式
|
||||
func (wf *Workflow) GetStringURL() string {
|
||||
return wf.ParsedURL.String()
|
||||
u := strings.Split(wf.ParsedURL.String(), "?")[0] + "?" + wf.GetCombineQuery().Encode()
|
||||
return u
|
||||
}
|
||||
|
||||
// SetURL 设置 url
|
||||
@@ -96,20 +111,26 @@ func (wf *Workflow) SetURL(srcURL string) *Workflow {
|
||||
return wf
|
||||
}
|
||||
|
||||
// GetURLQuery 获取Query参数
|
||||
func (wf *Workflow) GetURLQuery() url.Values {
|
||||
if wf.ParsedURL != nil {
|
||||
// GetQuery 获取Query参数
|
||||
func (wf *Workflow) GetQuery() url.Values {
|
||||
return wf.ParsedURL.Query()
|
||||
}
|
||||
}
|
||||
|
||||
// GetCombineQuery 获取Query参数
|
||||
func (wf *Workflow) GetCombineQuery() url.Values {
|
||||
if wf.ParsedURL != nil {
|
||||
vs := wf.ParsedURL.Query()
|
||||
return mergeMapList(wf.session.GetQuery(), vs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetURLQuery 设置Query参数
|
||||
func (wf *Workflow) SetURLQuery(query url.Values) *Workflow {
|
||||
// SetQuery 设置Query参数
|
||||
func (wf *Workflow) SetQuery(query url.Values) *Workflow {
|
||||
if query == nil {
|
||||
return wf
|
||||
}
|
||||
query = (url.Values)(mergeMapList(wf.session.Query, query))
|
||||
wf.ParsedURL.RawQuery = query.Encode()
|
||||
return wf
|
||||
}
|
||||
@@ -148,16 +169,14 @@ func (wf *Workflow) SetURLPath(path []string) *Workflow {
|
||||
}
|
||||
|
||||
// SetURLRawPath 设置Pa晚上参数
|
||||
func (wf *Workflow) Set晚上LRawPath(path string) *Workflow {
|
||||
wf.ParsedURL.Path = 晚上ath
|
||||
func (wf *Workflow) SetURLRawPath(path string) *Workflow {
|
||||
wf.ParsedURL.Path = path
|
||||
return wf
|
||||
}
|
||||
|
||||
// SetBodyParams 参数设晚上
|
||||
// SetBodyParams 参数设置
|
||||
func (wf *Workflow) SetBodyParams(params ...interface{}) *Workflow {
|
||||
if params == nil {
|
||||
return wf
|
||||
}
|
||||
if params != nil {
|
||||
|
||||
plen := len(params)
|
||||
defaultContentType := TypeURLENCODED
|
||||
@@ -171,9 +190,9 @@ func (wf *Workflow) SetBodyParams(params ...interface{}) *Workflow {
|
||||
}
|
||||
|
||||
if defaultContentType == TypeFormData {
|
||||
// TODO: form-data
|
||||
createMultipart(wf.Body, params)
|
||||
} else {
|
||||
|
||||
var values url.Values
|
||||
switch param := params[0].(type) {
|
||||
case map[string]string:
|
||||
@@ -190,14 +209,20 @@ func (wf *Workflow) SetBodyParams(params ...interface{}) *Workflow {
|
||||
case []byte:
|
||||
wf.Body.IOBody = param
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return wf
|
||||
}
|
||||
|
||||
// setHeaderRequest 设置request的头
|
||||
func setHeaderRequest(req *http.Request, wf *Workflow) {
|
||||
func mergeMapList(headers ...map[string][]string) map[string][]string {
|
||||
|
||||
set := make(map[string]map[string]int)
|
||||
for key, values := range wf.session.Header {
|
||||
merged := make(map[string][]string)
|
||||
|
||||
for _, header := range headers {
|
||||
for key, values := range header {
|
||||
for _, v := range values {
|
||||
if vs, ok := set[key]; ok {
|
||||
vs[v] = 1
|
||||
@@ -207,23 +232,25 @@ func setHeaderRequest(req *http.Request, wf *Workflow) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for key, values := range wf.Header {
|
||||
for _, v := range values {
|
||||
if vs, ok := set[key]; ok {
|
||||
vs[v] = 1
|
||||
} else {
|
||||
set[key] = make(map[string]int)
|
||||
set[key][v] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, mvalue := range set {
|
||||
for v := range mvalue {
|
||||
req.Header.Add(key, v)
|
||||
// merged.Add(key, v)
|
||||
if mergeValue, ok := merged[key]; ok {
|
||||
merged[key] = append(mergeValue, v)
|
||||
} else {
|
||||
merged[key] = []string{v}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
// setHeaderRequest 设置request的头
|
||||
func setHeaderRequest(req *http.Request, wf *Workflow) {
|
||||
req.Header = mergeMapList(req.Header, wf.session.Header, wf.Header)
|
||||
}
|
||||
|
||||
// setHeaderRequest 设置request的临时Cookie, 永久需要在session上设置cookie
|
||||
@@ -238,7 +265,7 @@ func setTempCookieRequest(req *http.Request, wf *Workflow) {
|
||||
// Execute 执行
|
||||
func (wf *Workflow) Execute() (*Response, error) {
|
||||
|
||||
req := buildBodyRequest(wf.Method, wf.GetStringURL(), wf.Body)
|
||||
req := buildBodyRequest(wf)
|
||||
|
||||
setHeaderRequest(req, wf)
|
||||
setTempCookieRequest(req, wf)
|
||||
@@ -246,6 +273,7 @@ func (wf *Workflow) Execute() (*Response, error) {
|
||||
if wf.session.auth != nil {
|
||||
req.SetBasicAuth(wf.session.auth.User, wf.session.auth.Password)
|
||||
}
|
||||
log.Println(req.Header)
|
||||
|
||||
resp, err := wf.session.client.Do(req)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user