合并
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 0000000..78f98ab
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,38 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[[constraint]]
+  name = "github.com/Sirupsen/logrus"
+  version = "1.3.0"
+
+[prune]
+  go-tests = true
+  unused-packages = true
+
+[[constraint]]
+  name = "gopkg.in/resty.v1"
+  version = "1.11.0"
diff --git a/go.mod b/go.mod
index aa7a343..db006bb 100644
--- a/go.mod
+++ b/go.mod
@@ -6,5 +6,5 @@
 	github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8
 	github.com/sirupsen/logrus v1.3.0
 	golang.org/x/text v0.3.0 // indirect
-	gopkg.in/resty.v1 v1.11.0 // indirect
+	gopkg.in/resty.v1 v1.11.0
 )
diff --git a/go.sum b/go.sum
index 6ea7118..55816e9 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,10 @@
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/resty.v1 v1.11.0 h1:z5nqGs/W/h91PLOc+WZefPj8rRZe8Ctlgxg/AtbJ+NE=
 gopkg.in/resty.v1 v1.11.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
diff --git a/webservice.go b/webservice.go
index abf2a17..abcc94d 100644
--- a/webservice.go
+++ b/webservice.go
@@ -1,6 +1,7 @@
 package swservice
 
 import (
+	"bytes"
 	"crypto/hmac"
 	"crypto/sha1"
 	"crypto/tls"
@@ -8,10 +9,8 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net"
 	"net/http"
-	"net/url"
 	"strconv"
 	"strings"
 	"sync"
@@ -19,8 +18,8 @@
 
 	"crypto/x509"
 
+	"gopkg.in/resty.v1"
 	log "github.com/sirupsen/logrus"
-	"github.com/franela/goreq"
 )
 
 var (
@@ -28,6 +27,8 @@
 	ErrBadCAPEM = errors.New("不正确的PEM文件")
 )
 
+var connectionTimeout = time.Duration(500) * time.Millisecond
+
 // WebSession web session object
 type WebSession struct {
 	// AppId app id
@@ -115,23 +116,17 @@
 	return 0.0
 }
 
-// DoGet send GET request
-func (w *WebSession) DoGet(uri string, params map[string]string,
-	timeout int) (*goreq.Response, error) {
+// doGet send GET request
+func (w *WebSession) doGet(uri string, params map[string]string,
+	timeout int) (*resty.Response, error) {
 
 	fullURL := w.BaseURL + uri
 
-	vl := url.Values{}
-
-	if params != nil {
-		for k, v := range params {
-			vl.Add(k, v)
-		}
-	}
-	fullURL = fullURL + "?" + vl.Encode()
-	return goreq.Request{Uri: fullURL,
-		Method:  "GET",
-		Timeout: time.Duration(timeout) * time.Second}.Do()
+	resty.SetTimeout(time.Duration(timeout) * time.Second)
+	resp, err := resty.R().
+		SetQueryParams(params).
+		Get(fullURL)
+	return resp, err
 }
 
 // GetTimestamp get time stamp format 20160103133455
@@ -181,8 +176,8 @@
 	return &transport
 }
 
-// DoPost send POST request
-func (w *WebSession) DoPost(uri string, param map[string]string) (*goreq.Response, error) {
+// doPost send POST request
+func (w *WebSession) doPost(uri string, param map[string]string) (*resty.Response, error) {
 	param["app_id"] = w.AppID
 	param["term_id"] = w.TermID
 	param["sign_method"] = "HMAC"
@@ -192,19 +187,13 @@
 	param["sign"] = w.Sign(w.AppID + w.TermID + w.sessionKey + ts)
 
 	fullURL := w.BaseURL + uri
-	data, err := json.Marshal(param)
-	if err != nil {
-		return nil, err
-	}
-	var r *goreq.Response
-	r, err = goreq.Request{
-		Uri:         fullURL,
-		Method:      "POST",
-		ContentType: "application/json",
-		Body:        data,
-		Timeout:     time.Duration(3) * time.Second}.Do()
-	if err != nil || r.StatusCode != 200 {
-		log.Errorf("Status=%v, err=%v", r, err)
+
+	r, err := resty.R().
+		SetHeader("Content-Type", "application/json").
+		SetBody(param).
+		Post(fullURL)
+	if err != nil || r.StatusCode() != 200 {
+		log.Errorf("Status=%v, err=%v", r.StatusCode(), err)
 	}
 	return r, err
 }
@@ -224,9 +213,6 @@
 
 // NewSession new session object
 func NewSession(appid, appsecret, termid, baseurl string, timeout int, sslVerify bool) *WebSession {
-	if transport, ok := goreq.DefaultTransport.(*http.Transport); ok {
-		transport.TLSClientConfig = nil
-	}
 	return &WebSession{
 		AppID:          appid,
 		AppSecret:      appsecret,
@@ -234,9 +220,7 @@
 		BaseURL:        baseurl,
 		DefaultTimeout: timeout,
 		sslVerify:      sslVerify,
-		httpConnectionPool: sync.Pool{New: func() interface{} {
-			return newTransport(baseurl, sslVerify)
-		}}}
+	}
 }
 
 // NewSessionWithCA new session ca
@@ -246,9 +230,11 @@
 	if !certs.AppendCertsFromPEM(ca) {
 		return nil, ErrBadCAPEM
 	}
-	if transport, ok := goreq.DefaultTransport.(*http.Transport); ok {
-		transport.TLSClientConfig = &tls.Config{RootCAs: certs}
-	}
+
+	resty.SetTLSClientConfig(&tls.Config{
+		InsecureSkipVerify: true,
+		RootCAs:            certs,
+	})
 
 	return &WebSession{
 		AppID:          appID,
@@ -271,17 +257,16 @@
 
 	params := make(map[string]string)
 	params["term_id"] = w.TermID
-	r, err := w.DoGet(uri, params, 5)
+	r, err := w.doGet(uri, params, 5)
 
 	if err != nil {
 		return "", err
 	}
-	if r.StatusCode != 200 {
+	if r.StatusCode() != 200 {
 		return "", errors.New("请求失败")
 	}
 
-	body, err := ioutil.ReadAll(r.Body)
-	defer r.Body.Close()
+	body := r.Body()
 
 	s := &FormJSON{}
 	err = json.Unmarshal(body, &s)
@@ -310,20 +295,18 @@
 	params["sign"] = w.Sign(token + params["timestamp"])
 	params["sign_method"] = "HMAC"
 
-	r, err := w.DoGet(uri, params, 5)
-	if r != nil {
-		defer r.Body.Close()
-	}
+	r, err := w.doGet(uri, params, 5)
 	if err != nil {
 		log.Errorf("err = %v\n", err)
 		return err
 	}
-	if r.StatusCode != 200 {
-		log.Errorf(" errcode = %v\n", r.StatusCode)
-		return fmt.Errorf("code %v", r.StatusCode)
+
+	if r.StatusCode() != 200 {
+		log.Errorf(" errcode = %v\n", r.StatusCode())
+		return fmt.Errorf("code %v", r.StatusCode())
 	}
 
-	body, err := ioutil.ReadAll(r.Body)
+	body := r.Body()
 
 	s := &FormJSON{}
 	err = json.Unmarshal(body, &s)
@@ -340,22 +323,18 @@
 	callData := request.Serialize()
 	params := make(map[string]string)
 	params["funcdata"] = callData
-	r, err := w.DoPost("/ecardservice/ecardapi", params)
 
-	if r != nil {
-		defer r.Body.Close()
-	}
+	r, err := w.doPost("/ecardservice/ecardapi", params)
 	if err != nil {
 		log.Errorf(" err = %v\n", err)
 		return nil, err
 	}
 
-	if r.StatusCode != 200 {
-		return nil, fmt.Errorf("Request StatusCode:%v", r.StatusCode)
+	if r.StatusCode() != 200 {
+		return nil, fmt.Errorf("Request StatusCode:%v", r.StatusCode())
 	}
 
-	body, err := ioutil.ReadAll(r.Body)
-	return NewMessageReader(body), nil
+	return NewMessageReader(r.Body()), nil
 }
 
 // CallService call epay service
@@ -365,58 +344,61 @@
 	return w.CallService2(path, params, timeout, signField...)
 }
 
+// SetConnectionTimeout set global connection timeout
+func SetConnectionTimeout(ms int) {
+	connectionTimeout = time.Duration(ms) * time.Millisecond
+	resty.SetTimeout(connectionTimeout)
+}
+
 // CallService2 call epay service
 func (w *WebSession) CallService2(path string, params map[string]interface{}, timeout int,
 	signField ...string) (response *ServiceResponse, err error) {
 	err = nil
-	params["app_id"] = w.AppID
-	params["term_id"] = w.TermID
-	ts := w.GetTimestamp()
-	params["timestamp"] = ts
 
-	vl := &url.Values{}
-	for k, v := range params {
-		vl.Set(k, fmt.Sprintf("%v", v))
+	formData := make(map[string]string)
+	if params != nil {
+		for k, v := range params {
+			formData[k] = fmt.Sprintf("%v", v)
+		}
 	}
+	formData["app_id"] = w.AppID
+	formData["term_id"] = w.TermID
+	ts := w.GetTimestamp()
+	formData["timestamp"] = ts
 
 	signData := ""
 	for _, k := range signField {
-		if v, ok := params[k]; ok {
-			signData += fmt.Sprintf("%v", v)
+		if v, ok := formData[k]; ok {
+			signData += v
 		}
 	}
 	signData += ts + w.sessionKey
-	vl.Set("sign_method", "HMAC")
 	log.Debugf("Sign: key[%v] data[%v]\n", w.sessionKey, signData)
-	vl.Set("sign", w.SignWithKey(w.AppSecret, signData))
+	formData["sign_method"] = "HMAC"
+	formData["sign"] = w.SignWithKey(w.AppSecret, signData)
 
 	fullURL := w.BaseURL + path
 	log.Debugf("CallService: %v\n", fullURL)
-	var r *goreq.Response
-	r, err = goreq.Request{
-		Uri:         fullURL,
-		Accept:      "application/json",
-		ContentType: "application/x-www-form-urlencoded",
-		Method:      "POST",
-		Timeout:     time.Duration(timeout) * time.Second,
-		Body:        vl.Encode()}.Do()
+	r, err := resty.R().
+		SetHeader("Accept", "application/json").
+		SetFormData(formData).
+		Post(fullURL)
 	if err != nil {
 		log.Errorf("Status=%v, err=%v", r, err)
 		return
 	}
-	if r != nil && r.Body != nil {
-		defer r.Body.Close()
-	}
 
-	if r.StatusCode != 200 {
-		log.Errorf("Request Error %v\n", r.StatusCode)
-		err = fmt.Errorf("Request Error, StatusCode : %v", r.StatusCode)
+	if r.StatusCode() != 200 {
+		log.Errorf("Request Error %v\n", r.StatusCode())
+		err = fmt.Errorf("Request Error, StatusCode : %v", r.StatusCode())
 		return
 	}
 
-	body, err := ioutil.ReadAll(r.Body)
 	var s interface{}
-	err = json.Unmarshal(body, &s)
+	decoder := json.NewDecoder(bytes.NewBuffer(r.Body()))
+	decoder.UseNumber() // 此处能够保证bigint的精度
+	err = decoder.Decode(&s)
+	// err = json.Unmarshal(r.Body(), &s)
 	if err != nil {
 		log.Errorf("json unmarshal err %v", err)
 		return
diff --git a/webservice_test.go b/webservice_test.go
index 00393a2..4c3cb08 100644
--- a/webservice_test.go
+++ b/webservice_test.go
@@ -1,6 +1,7 @@
 package swservice
 
 import (
+	"fmt"
 	"testing"
 )
 
@@ -37,16 +38,38 @@
 )
 
 func TestUseHTTP(t *testing.T) {
-	uri := "http://vb-docker:8443/epayapi/services"
+	uri := "http://ykt.supwisdom.com:9116/epayapi/services"
 	session := NewSession(appID, appSecret, termID, uri, 3, true)
 	err := session.Auth()
 	if err != nil {
 		t.Errorf("Auth Error: %v", err)
 	}
+
+	r, err := session.CallService2("/common/servicecheck",
+		make(map[string]interface{}), 3)
+	if err != nil {
+		t.Errorf("Request Error: %v", err)
+	} else {
+		fmt.Printf("hostdatetime: %v\n", r.GetStrValue("hostdatetime"))
+	}
+
+	r, err = session.CallService2("/v5/manage/pos/gettoken",
+		map[string]interface{}{
+			"devphyid": "30000004",
+		}, 3, "devphyid")
+
+	if err != nil {
+		t.Errorf("Request Error: %v", err)
+	} else if r.GetIntValue("retcode") != 0 {
+		t.Errorf("get device token error, ret=%v", r.GetIntValue("retcode"))
+	} else {
+		fmt.Printf("ret=%v, devtoken: %v\n", r.GetIntValue("retcode"),
+			r.GetStrValue("devtoken"))
+	}
 }
 
 func TestUseHTTPS(t *testing.T) {
-	uri := "https://vb-docker:8443/epayapi/services"
+	uri := "https://ykt.supwisdom.com/epayapi/services"
 	session, err := NewSessionWithCA(appID, appSecret, termID, uri, 3, []byte(caPEM))
 	if err != nil {
 		t.Error("New Session , ", err)
@@ -60,7 +83,7 @@
 }
 
 func TestUseSecureHTTPS(t *testing.T) {
-	uri := "https://www.baidu.com"
+	uri := "https://ykt.supwisdom.com/epayapi/services"
 	session := NewSession(appID, appSecret, termID, uri, 3, true)
 	err := session.Auth()
 	if err != nil {