From ee4e88594d4b8eebf601bdbe452df7b95ef681e1 Mon Sep 17 00:00:00 2001 From: gazebo Date: Tue, 26 Jun 2018 15:26:39 +0800 Subject: [PATCH] - elm and weixin token refresh. --- platformapi/dadaapi/dadaapi.go | 6 +- platformapi/elmapi/elmapi.go | 61 +++++++++++-- platformapi/elmapi/elmapi_test.go | 12 ++- platformapi/jdapi/jdapi.go | 21 +---- platformapi/jdapi/jdapi_test.go | 2 +- platformapi/weixinapi/weixinapi.go | 113 ++++++++++++++++++++++++ platformapi/weixinapi/weixinapi_test.go | 40 +++++++++ utils/utils.go | 16 ++++ 8 files changed, 241 insertions(+), 30 deletions(-) create mode 100644 platformapi/weixinapi/weixinapi.go create mode 100644 platformapi/weixinapi/weixinapi_test.go diff --git a/platformapi/dadaapi/dadaapi.go b/platformapi/dadaapi/dadaapi.go index efa304f7..a9d2554b 100644 --- a/platformapi/dadaapi/dadaapi.go +++ b/platformapi/dadaapi/dadaapi.go @@ -13,8 +13,8 @@ import ( ) const ( - sandboxURL = "http://newopen.qa.imdada.cn/" - prodURL = "http://newopen.imdada.cn/" + sandboxURL = "http://newopen.qa.imdada.cn" + prodURL = "http://newopen.imdada.cn" signKey = "signature" ) @@ -109,7 +109,7 @@ func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *R } params2[signKey] = a.signParams(params2) params2Bytes := utils.MustMarshal(params2) - request, _ := http.NewRequest("POST", a.url+action, bytes.NewReader(params2Bytes)) + request, _ := http.NewRequest("POST", a.url+"/"+action, bytes.NewReader(params2Bytes)) request.Header.Set("Content-Type", "application/json") err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) { diff --git a/platformapi/elmapi/elmapi.go b/platformapi/elmapi/elmapi.go index 988d215f..77a5aafb 100644 --- a/platformapi/elmapi/elmapi.go +++ b/platformapi/elmapi/elmapi.go @@ -2,6 +2,7 @@ package elmapi import ( "crypto/md5" + "encoding/base64" "fmt" "io/ioutil" "net/http" @@ -15,9 +16,13 @@ import ( ) const ( - sandboxURL = "https://open-api-sandbox.shop.ele.me/api/v1/" - prodURL = "https://open-api.shop.ele.me/api/v1/" - signKey = "signature" + sandboxURL = "https://open-api-sandbox.shop.ele.me/api/v1" + snadboxTokenURL = "https://open-api-sandbox.shop.ele.me/token" + + prodURL = "https://open-api.shop.ele.me/api/v1" + prodTokenURL = "https://open-api.shop.ele.me/token" + + signKey = "signature" ) type ResponseResult struct { @@ -26,10 +31,17 @@ type ResponseResult struct { Error map[string]interface{} } +type TokenInfo struct { + AccessToken string `json:"access_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` +} + type API struct { token string appKey string secret string + isProd bool url *url.URL client *http.Client config *platformapi.APIConfig @@ -54,14 +66,15 @@ func New(token, appKey, secret string, isProd bool, config ...*platformapi.APICo token: token, appKey: appKey, secret: secret, + isProd: isProd, client: &http.Client{Timeout: curConfig.ClientTimeout}, config: &curConfig, } if isProd { - api.url, _ = url.Parse(prodURL) + api.url, _ = url.Parse(prodURL + "/") } else { - api.url, _ = url.Parse(sandboxURL) + api.url, _ = url.Parse(sandboxURL + "/") } return api } @@ -153,3 +166,41 @@ func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *R return retVal, err } + +func (a *API) getTokenURL() string { + if a.isProd { + return prodTokenURL + } + return snadboxTokenURL +} + +func (a *API) RefreshToken() (retVal *TokenInfo, err error) { + params2 := make(url.Values) + params2["grant_type"] = []string{"client_credentials"} + params2["scope"] = []string{"all"} + // baseapi.SugarLogger.Debug(params2.Encode()) + request, _ := http.NewRequest("POST", a.getTokenURL(), strings.NewReader(params2.Encode())) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + request.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(a.appKey+":"+a.secret))) + + err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) { + jsonResult1, err := utils.HTTPResponse2Json(response) + if err != nil { + return platformapi.ErrLevelGeneralFail, err + } + retVal = &TokenInfo{} + + if accessToken, ok := jsonResult1["access_token"]; ok { + retVal.AccessToken = accessToken.(string) + retVal.TokenType = jsonResult1["token_type"].(string) + retVal.ExpiresIn = int(utils.MustInterface2Int64(jsonResult1["expires_in"])) + + // update my token too. + a.token = retVal.AccessToken + return platformapi.ErrLevelSuccess, nil + } + return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong + }) + + return retVal, err +} diff --git a/platformapi/elmapi/elmapi_test.go b/platformapi/elmapi/elmapi_test.go index 55f06f30..90cc6117 100644 --- a/platformapi/elmapi/elmapi_test.go +++ b/platformapi/elmapi/elmapi_test.go @@ -20,10 +20,10 @@ func init() { baseapi.Init(sugarLogger) // sandbox - // elmapi = New("b4f7e424475c3758c111dc60ceec3e2a", "RwT214gAsS", "56afff4b9ebd8a7eb532d18fa33f17be57f9b9db", false) + elmapi = New("f22acad55e8b11ae146ad9295e20cf4e", "RwT214gAsS", "56afff4b9ebd8a7eb532d18fa33f17be57f9b9db", false) // prod - elmapi = New("bab2a27f99562f394b411dbb9a6214da", "KLRDcOZGrk", "1fc221f8265506531da36fb613d5f5ad673f2e9a", true) + // elmapi = New("bab2a27f99562f394b411dbb9a6214da", "KLRDcOZGrk", "1fc221f8265506531da36fb613d5f5ad673f2e9a", true) } func TestTest(t *testing.T) { @@ -62,3 +62,11 @@ func TestCallbackSign(t *testing.T) { t.Fatal(response, msg) } } + +func TestRefreshToken(t *testing.T) { + result, err := elmapi.RefreshToken() + if err != nil { + t.Fatal(err.Error()) + } + sugarLogger.Debug(result) +} diff --git a/platformapi/jdapi/jdapi.go b/platformapi/jdapi/jdapi.go index 85e25dc0..13c30d97 100644 --- a/platformapi/jdapi/jdapi.go +++ b/platformapi/jdapi/jdapi.go @@ -40,7 +40,7 @@ const ( ) const ( - prodURL = "https://openo2o.jd.com/djapi/%s" + prodURL = "https://openo2o.jd.com/djapi" signKey = "sign" AllPage = 0 DefaultPageSize = 50 @@ -107,23 +107,6 @@ func (a *API) signParams(jdParams map[string]interface{}) string { return fmt.Sprintf("%X", md5.Sum([]byte(allStr))) } -func generateURL(baseURL, apiStr string, params map[string]interface{}) string { - fullURL := "" - - if params != nil { - for k, v := range params { - if fullURL == "" { - fullURL = "?" - } else { - fullURL += "&" - } - fullURL += k + "=" + url.QueryEscape(fmt.Sprint(v)) - } - } - - return fmt.Sprintf(baseURL, apiStr) + fullURL -} - func New(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { @@ -159,7 +142,7 @@ func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal sign := a.signParams(params) params[signKey] = sign - url, _ := url.Parse(generateURL(prodURL, apiStr, params)) + url, _ := url.Parse(utils.GenerateGetURL(prodURL, apiStr, params)) request := &http.Request{ Method: "GET", URL: url, diff --git a/platformapi/jdapi/jdapi_test.go b/platformapi/jdapi/jdapi_test.go index e8f520c3..5ac07180 100644 --- a/platformapi/jdapi/jdapi_test.go +++ b/platformapi/jdapi/jdapi_test.go @@ -84,7 +84,7 @@ func TestGenerateURL(t *testing.T) { params["key"] = "v" params["key2"] = "v2" - fullURL := generateURL(prodURL, "address/allcities", params) + fullURL := utils.GenerateGetURL(prodURL, "address/allcities", params) response, err := http.Get(fullURL) if err != nil { diff --git a/platformapi/weixinapi/weixinapi.go b/platformapi/weixinapi/weixinapi.go new file mode 100644 index 00000000..ecb74a48 --- /dev/null +++ b/platformapi/weixinapi/weixinapi.go @@ -0,0 +1,113 @@ +package weixinapi + +import ( + "net/http" + "net/url" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + prodURL = "https://api.weixin.qq.com" +) + +const ( + ResponseCodeBusy = -1 + ResponseCodeSuccess = 0 +) + +type TokenInfo struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` +} + +type ErrorInfo struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` +} + +type API struct { + token string + appID string + secret string + client *http.Client + config *platformapi.APIConfig +} + +func New(appID, secret string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + return &API{ + appID: appID, + secret: secret, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + +func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal interface{}, err error) { + if params == nil { + panic("params is nil!") + } + + params2 := make(map[string]interface{}) + for k, v := range params { + params2[k] = v + } + params2["appid"] = a.appID + params2["secret"] = a.secret + url, _ := url.Parse(utils.GenerateGetURL(prodURL, action, params2)) + // baseapi.SugarLogger.Debug(url.String()) + request := &http.Request{ + Method: "GET", + URL: url, + } + err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) { + jsonResult1, err := utils.HTTPResponse2Json(response) + if err != nil { + return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong + } + + var errInfo *ErrorInfo + // 微信的返回值,在错误与正常情况下,结构是完全不一样的 + if errCode, ok := jsonResult1["errcode"]; ok { + errInfo = &ErrorInfo{ + ErrCode: int(utils.MustInterface2Int64(errCode)), + ErrMsg: jsonResult1["errmsg"].(string), + } + } else { + retVal = &TokenInfo{ + AccessToken: jsonResult1["access_token"].(string), + ExpiresIn: int(utils.MustInterface2Int64(jsonResult1["expires_in"])), + } + } + + if retVal != nil { + return platformapi.ErrLevelSuccess, nil + } + baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, code:%v", jsonResult1, errInfo.ErrCode) + newErr := utils.NewErrorIntCode(errInfo.ErrMsg, errInfo.ErrCode) + if errInfo.ErrCode == ResponseCodeBusy { + return platformapi.ErrLevelRecoverableErr, newErr + } + return platformapi.ErrLevelCodeIsNotOK, newErr + }) + + return retVal, err +} + +func (a *API) RefreshToken() (tokenInfo *TokenInfo, err error) { + result, err := a.AccessAPI("cgi-bin/token", utils.Params2Map("grant_type", "client_credential")) + if err != nil { + return nil, err + } + tokenInfo = result.(*TokenInfo) + + // update my token too. + a.token = tokenInfo.AccessToken + return tokenInfo, nil +} diff --git a/platformapi/weixinapi/weixinapi_test.go b/platformapi/weixinapi/weixinapi_test.go new file mode 100644 index 00000000..8263c04e --- /dev/null +++ b/platformapi/weixinapi/weixinapi_test.go @@ -0,0 +1,40 @@ +package weixinapi + +import ( + "testing" + + "git.rosy.net.cn/baseapi" + + "git.rosy.net.cn/baseapi/utils" + "go.uber.org/zap" +) + +var ( + weixinapi *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + weixinapi = New("wxbf235770edaabc5c", "ba32b269a068a5b72486a0beafd171e8") +} + +func handleError(t *testing.T, err error) { + if err != nil { + sugarLogger.Debug(err) + t.Fatal(err.Error()) + } +} +func TestTest(t *testing.T) { + sugarLogger.Debug(utils.GetCurTimeStr()) +} + +func TestRefreshToken(t *testing.T) { + result, err := weixinapi.RefreshToken() + if err != nil { + t.Fatal(err.Error()) + } + sugarLogger.Debug(result) +} diff --git a/utils/utils.go b/utils/utils.go index 8d671fb7..36dc867a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "net/http" + "net/url" "reflect" "strconv" "strings" @@ -232,3 +233,18 @@ func Params2Map(key1, value1 interface{}, kv ...interface{}) (retVal map[string] return retVal } + +func GenerateGetURL(baseURL, apiStr string, params map[string]interface{}) string { + queryString := "" + if params != nil { + for k, v := range params { + if queryString == "" { + queryString = "?" + } else { + queryString += "&" + } + queryString += k + "=" + url.QueryEscape(fmt.Sprint(v)) + } + } + return baseURL + "/" + apiStr + queryString +}