mirror of
https://gitee.com/zhangsken/aliyunpan.git
synced 2026-10-16 02:23:49 +08:00
optimize token refresh task
This commit is contained in:
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/tickstep/aliyunpan/internal/config"
|
||||
"github.com/tickstep/aliyunpan/internal/file/downloader"
|
||||
"github.com/tickstep/aliyunpan/internal/functions/pandownload"
|
||||
"github.com/tickstep/aliyunpan/internal/functions/panlogin"
|
||||
"github.com/tickstep/aliyunpan/internal/taskframework"
|
||||
"github.com/tickstep/aliyunpan/internal/utils"
|
||||
"github.com/tickstep/aliyunpan/library/requester/transfer"
|
||||
@@ -628,7 +629,8 @@ func RunAlbumDownloadFile(albumNames []string, options *DownloadOptions) {
|
||||
go func(flag *int32) {
|
||||
for atomic.LoadInt32(flag) == 0 {
|
||||
time.Sleep(time.Duration(1) * time.Minute)
|
||||
if RefreshWebTokenInNeed(activeUser, config.Config.DeviceName) {
|
||||
re := RefreshWebTokenInNeed(activeUser)
|
||||
if re.Code == panlogin.SUCCESS {
|
||||
logger.Verboseln("update access token for download task")
|
||||
}
|
||||
}
|
||||
|
||||
+125
-22
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/tickstep/aliyunpan/internal/utils"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"path"
|
||||
@@ -142,9 +143,9 @@ func NewWebLoginToken(accessToken string, expired int64) aliyunpan_web.WebLoginT
|
||||
}
|
||||
|
||||
// RefreshWebTokenInNeed 刷新 webapi access token
|
||||
func RefreshWebTokenInNeed(activeUser *config.PanUser, deviceName string) bool {
|
||||
func RefreshWebTokenInNeed(activeUser *config.PanUser) *panlogin.CommonResultError {
|
||||
if activeUser == nil {
|
||||
return false
|
||||
return panlogin.NewCommonResultError("activeUser is nil")
|
||||
}
|
||||
|
||||
// refresh expired web token
|
||||
@@ -153,7 +154,7 @@ func RefreshWebTokenInNeed(activeUser *config.PanUser, deviceName string) bool {
|
||||
cz := time.FixedZone("CST", 8*3600) // 东8区
|
||||
expiredTime := time.Unix(activeUser.WebapiToken.Expired, 0).In(cz)
|
||||
now := time.Now()
|
||||
if (expiredTime.Unix() - now.Unix()) <= (2 * 60) { // 有效期小于2min就刷新
|
||||
if (expiredTime.Unix() - now.Unix()) <= (10 * 60) { // 有效期小于10min就刷新
|
||||
pluginManger := plugins.NewPluginManager(config.GetPluginDir())
|
||||
plugin, _ := pluginManger.GetPlugin()
|
||||
params := &plugins.UserTokenRefreshFinishParams{
|
||||
@@ -167,9 +168,12 @@ func RefreshWebTokenInNeed(activeUser *config.PanUser, deviceName string) bool {
|
||||
// need update refresh token
|
||||
logger.Verboseln("web access token expired, get new from server")
|
||||
loginHelper := panlogin.NewLoginHelper(config.DefaultTokenServiceWebHost)
|
||||
wt, e := loginHelper.GetWebapiNewToken(activeUser.TicketId, activeUser.UserId, activeUser.PanClient().WebapiPanClient().GetAccessToken())
|
||||
if e != nil {
|
||||
logger.Verboseln("get web token from server error: ", e)
|
||||
wt, re := loginHelper.GetWebapiNewToken(activeUser.TicketId, activeUser.UserId, activeUser.PanClient().WebapiPanClient().GetAccessToken())
|
||||
if re != nil {
|
||||
logger.Verboseln("get web token from server error: ", re.Msg)
|
||||
if re.Code != panlogin.SUCCESS {
|
||||
return re
|
||||
}
|
||||
}
|
||||
if wt != nil {
|
||||
params.Result = "success"
|
||||
@@ -191,42 +195,51 @@ func RefreshWebTokenInNeed(activeUser *config.PanUser, deviceName string) bool {
|
||||
}
|
||||
|
||||
// create new signature
|
||||
_, e := activeUser.PanClient().WebapiPanClient().CreateSession(nil)
|
||||
if e != nil {
|
||||
logger.Verboseln("call CreateSession error in RefreshWebTokenInNeed: " + e.Error())
|
||||
_, e1 := activeUser.PanClient().WebapiPanClient().CreateSession(nil)
|
||||
if e1 != nil {
|
||||
logger.Verboseln("call CreateSession error in RefreshWebTokenInNeed: " + e1.Error())
|
||||
}
|
||||
return &panlogin.CommonResultError{
|
||||
Code: 0,
|
||||
Msg: "",
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
// token refresh error
|
||||
// if token has expired, callback plugin api for notify
|
||||
if now.Unix() >= expiredTime.Unix() {
|
||||
params.Result = "fail"
|
||||
params.Message = e.Error()
|
||||
params.Message = re.Msg
|
||||
params.OldToken = activeUser.WebapiToken.AccessToken
|
||||
if er1 := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(activeUser), params); er1 != nil {
|
||||
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er1.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return &panlogin.CommonResultError{
|
||||
Code: 0,
|
||||
Msg: "web token is validate, not need to refresh",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
return panlogin.NewCommonResultError("activeUser is invalidate")
|
||||
}
|
||||
|
||||
// RefreshOpenTokenInNeed 刷新 openapi access token
|
||||
func RefreshOpenTokenInNeed(activeUser *config.PanUser) bool {
|
||||
func RefreshOpenTokenInNeed(activeUser *config.PanUser) *panlogin.CommonResultError {
|
||||
if activeUser == nil {
|
||||
return false
|
||||
return panlogin.NewCommonResultError("activeUser is nil")
|
||||
}
|
||||
|
||||
// OpenAPI的token只有2个小时有效期,需要在token过期之前进行刷新并把获取到的新token存储在本地
|
||||
// refresh expired openapi token
|
||||
if activeUser.PanClient().OpenapiPanClient() != nil {
|
||||
if activeUser.OpenapiToken != nil && len(activeUser.OpenapiToken.AccessToken) > 0 {
|
||||
cz := time.FixedZone("CST", 8*3600) // 东8区
|
||||
expiredTime := time.Unix(activeUser.OpenapiToken.Expired, 0).In(cz)
|
||||
now := time.Now().In(cz)
|
||||
if (expiredTime.Unix() - now.Unix()) <= (2 * 60) { // 有效期小于2min就刷新
|
||||
if (expiredTime.Unix() - now.Unix()) <= (10 * 60) { // 有效期小于10min就刷新
|
||||
pluginManger := plugins.NewPluginManager(config.GetPluginDir())
|
||||
plugin, _ := pluginManger.GetPlugin()
|
||||
params := &plugins.UserTokenRefreshFinishParams{
|
||||
@@ -240,11 +253,15 @@ func RefreshOpenTokenInNeed(activeUser *config.PanUser) bool {
|
||||
// need update refresh token
|
||||
logger.Verboseln("openapi access token expired, get new from server")
|
||||
loginHelper := panlogin.NewLoginHelper(config.DefaultTokenServiceWebHost)
|
||||
wt, e := loginHelper.GetOpenapiNewToken(activeUser.TicketId, activeUser.UserId, activeUser.PanClient().OpenapiPanClient().GetAccessToken())
|
||||
if e != nil {
|
||||
logger.Verboseln("get openapi token from server error: ", e)
|
||||
wt, re := loginHelper.GetOpenapiNewToken(activeUser.TicketId, activeUser.UserId, activeUser.PanClient().OpenapiPanClient().GetAccessToken())
|
||||
if re != nil {
|
||||
logger.Verboseln("get openapi token from server error: ", re.Msg)
|
||||
if re.Code != panlogin.SUCCESS {
|
||||
return re
|
||||
}
|
||||
}
|
||||
if wt != nil {
|
||||
// 存储新token到本地
|
||||
params.Result = "success"
|
||||
params.OldToken = activeUser.OpenapiToken.AccessToken
|
||||
params.NewToken = wt.AccessToken
|
||||
@@ -261,23 +278,109 @@ func RefreshOpenTokenInNeed(activeUser *config.PanUser) bool {
|
||||
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er1.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
return &panlogin.CommonResultError{
|
||||
Code: 0,
|
||||
Msg: "",
|
||||
}
|
||||
} else {
|
||||
// token refresh error
|
||||
// if token has expired, callback plugin api for notify
|
||||
if now.Unix() >= expiredTime.Unix() {
|
||||
params.Result = "fail"
|
||||
params.Message = e.Error()
|
||||
params.OldToken = activeUser.WebapiToken.AccessToken
|
||||
params.Message = re.Msg
|
||||
params.OldToken = activeUser.OpenapiToken.AccessToken
|
||||
if er1 := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(activeUser), params); er1 != nil {
|
||||
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er1.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return &panlogin.CommonResultError{
|
||||
Code: 0,
|
||||
Msg: "openapi token is validate, not need to refresh",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
return panlogin.NewCommonResultError("activeUser is invalidate")
|
||||
}
|
||||
|
||||
// AutomaticallyRefreshTokenTask 自动刷新Token的后台任务
|
||||
func AutomaticallyRefreshTokenTask() {
|
||||
go func() {
|
||||
// 检测延迟时间(分钟)
|
||||
delayMinuteTime := time.Duration(1) * time.Minute
|
||||
//delayMinuteTime := time.Duration(10) * time.Second // for test
|
||||
// 请求重试次数
|
||||
attempt := 1
|
||||
for {
|
||||
// Token刷新进程,不管是CLI命令行模式,还是直接命令模式,本刷新任务都会执行
|
||||
time.Sleep(delayMinuteTime) // 定时器,每1分钟调用一次
|
||||
|
||||
// 重新加载配置文件
|
||||
ReloadConfigFunc(nil)
|
||||
activeUser := config.Config.ActiveUser()
|
||||
if activeUser != nil && activeUser.UserId != "" && activeUser.PanClient() != nil {
|
||||
// 刷新Openapi端Token
|
||||
errResult := RefreshOpenTokenInNeed(activeUser)
|
||||
attempt += 1
|
||||
if errResult != nil && errResult.Code == panlogin.SUCCESS {
|
||||
// 刷新成功,重置定时器
|
||||
attempt = 1
|
||||
delayMinuteTime = time.Duration(1) * time.Minute
|
||||
|
||||
// 刷新Web端Token
|
||||
RefreshWebTokenInNeed(activeUser)
|
||||
|
||||
// 保存新token到配置文件
|
||||
SaveConfigFunc(nil)
|
||||
} else {
|
||||
// 刷新Token失败
|
||||
logger.Verboseln("刷新Token失败:", errResult.Msg)
|
||||
if errResult.Code == panlogin.ERROR_NEED_LOGIN_AGAIN {
|
||||
// token已经失效,需要重新登录
|
||||
logger.Verboseln("token已经失效,需要重新登录,退出自动刷新Token任务")
|
||||
return
|
||||
} else if errResult.Code == panlogin.ERROR {
|
||||
// 访问错误
|
||||
delayMinuteTime = ProgressiveBackoffAlg(attempt)
|
||||
} else if errResult.Code == panlogin.ERROR_TOO_MANY_REQUESTS {
|
||||
// 请求过于频繁
|
||||
delayMinuteTime = ProgressiveBackoffAlg(attempt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// ProgressiveBackoffAlg 指数退降算法
|
||||
func ProgressiveBackoffAlg(attempt int) time.Duration {
|
||||
maxRetries := 120
|
||||
baseDelay := float64(1)
|
||||
maxDelay := float64(1440)
|
||||
|
||||
if attempt >= maxRetries {
|
||||
return time.Duration(maxDelay) * time.Minute
|
||||
}
|
||||
|
||||
// 计算当前延迟
|
||||
var delay float64
|
||||
if attempt < 100 {
|
||||
// 前 100 次:线性增长 + 小指数基数(缓慢增加)
|
||||
delay = baseDelay * (1 + float64(attempt)/5) // 调整分母控制增长速度
|
||||
} else {
|
||||
// 100 次后:标准指数退避
|
||||
delay = baseDelay * math.Pow(1.5, float64(attempt-100))
|
||||
if delay > maxDelay {
|
||||
delay = maxDelay
|
||||
}
|
||||
}
|
||||
|
||||
// 添加随机抖动(最多 20% 的扰动)
|
||||
jitterSec := rand.Float64() * delay * 0.2 // ±20% 随机扰动
|
||||
delay += jitterSec
|
||||
return time.Duration(delay * float64(time.Minute))
|
||||
}
|
||||
|
||||
func isIncludeFile(pattern string, fileName string) bool {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProgressiveBackoffAlg(t *testing.T) {
|
||||
for attempt := 1; attempt <= 150; attempt++ {
|
||||
delayTime := ProgressiveBackoffAlg(attempt)
|
||||
fmt.Printf("第%d次,延迟分钟: %.2f\n", attempt, delayTime.Minutes())
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ doOpenLoginAct:
|
||||
tryRefreshOpenToken = false
|
||||
wt, e := loginHelper.GetOpenapiNewToken(ticketId, userId, openapiToken.AccessToken)
|
||||
if e != nil {
|
||||
logger.Verboseln("get openapi token from server error: ", e)
|
||||
logger.Verboseln("get openapi token from server error: ", e.Msg)
|
||||
return nil, apierror.NewFailedApiError("get new openapi token error, try login again")
|
||||
}
|
||||
if wt != nil {
|
||||
@@ -169,7 +169,11 @@ doOpenLoginAct:
|
||||
AccessToken: wt.AccessToken,
|
||||
Expired: wt.Expired,
|
||||
}
|
||||
|
||||
// 检查token有效期
|
||||
}
|
||||
|
||||
// 回到token检测流程,必须确保token是有效
|
||||
time.Sleep(time.Duration(1) * time.Second)
|
||||
goto doOpenLoginAct
|
||||
}
|
||||
@@ -207,7 +211,7 @@ doWebLoginAct:
|
||||
tryRefreshWebToken = false
|
||||
wt, e := loginHelper.GetWebapiNewToken(ticketId, userId, webapiToken.AccessToken)
|
||||
if e != nil {
|
||||
logger.Verboseln("get web token from server error: ", e)
|
||||
logger.Verboseln("get web token from server error: ", e.Msg)
|
||||
}
|
||||
if wt != nil {
|
||||
webapiToken = &PanClientToken{
|
||||
|
||||
@@ -21,8 +21,19 @@ type LoginHelper struct {
|
||||
webHost string
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
type respCommonResult struct {
|
||||
const (
|
||||
// SUCCESS 成功
|
||||
SUCCESS = 0
|
||||
// ERROR 失败
|
||||
ERROR = 500
|
||||
// ERROR_TOO_MANY_REQUESTS 请求太频繁,已被限流
|
||||
ERROR_TOO_MANY_REQUESTS = 429
|
||||
// ERROR_NEED_LOGIN_AGAIN Token已经过期,需要重新登录
|
||||
ERROR_NEED_LOGIN_AGAIN = 100004
|
||||
)
|
||||
|
||||
// CommonResultError 通用接口错误
|
||||
type CommonResultError struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
@@ -57,6 +68,13 @@ type CommonTokenEntity struct {
|
||||
Webapi *LoginTokenResult `json:"webapi"`
|
||||
}
|
||||
|
||||
func NewCommonResultError(msg string) *CommonResultError {
|
||||
return &CommonResultError{
|
||||
Code: 500,
|
||||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func NewLoginHelper(webHost string) *LoginHelper {
|
||||
return &LoginHelper{
|
||||
webHost: webHost,
|
||||
@@ -93,7 +111,7 @@ func (h *LoginHelper) GetQRCodeLoginUrl(keyStr string) (*QRCodeUrlResult, error)
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
@@ -154,7 +172,7 @@ func (h *LoginHelper) GetQRCodeLoginResult(tokenId string) (*QRCodeLoginResult,
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
@@ -204,7 +222,7 @@ func (h *LoginHelper) GetRefreshToken(tokenId string) (*QRCodeLoginResult, error
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
@@ -269,7 +287,7 @@ func (h *LoginHelper) ParseSecureRefreshToken(keyStr, secureRefreshToken string)
|
||||
}
|
||||
|
||||
// GetWebapiNewToken 获取Webapi Token
|
||||
func (h *LoginHelper) GetWebapiNewToken(ticketId, userId, oldAccessToken string) (*LoginTokenResult, error) {
|
||||
func (h *LoginHelper) GetWebapiNewToken(ticketId, userId, oldAccessToken string) (*LoginTokenResult, *CommonResultError) {
|
||||
fullUrl := strings.Builder{}
|
||||
fmt.Fprintf(&fullUrl, "%s/auth/tickstep/aliyunpan/token/webapi/%s/refresh?userId=%s",
|
||||
h.webHost, ticketId, userId)
|
||||
@@ -287,26 +305,29 @@ func (h *LoginHelper) GetWebapiNewToken(ticketId, userId, oldAccessToken string)
|
||||
body, err := client.Fetch("GET", fullUrl.String(), nil, header)
|
||||
if err != nil {
|
||||
logger.Verboseln("get web token result error ", err)
|
||||
return nil, err
|
||||
return nil, NewCommonResultError(err.Error())
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
return nil, NewCommonResultError(err1.Error())
|
||||
}
|
||||
if commonResult.Code != 0 {
|
||||
return nil, fmt.Errorf(commonResult.Msg)
|
||||
return nil, commonResult
|
||||
}
|
||||
|
||||
errResp := &LoginHttpResult{}
|
||||
if err1 := json.Unmarshal(body, errResp); err1 != nil {
|
||||
logger.Verboseln("parse result json error ", err1)
|
||||
return nil, err1
|
||||
return nil, NewCommonResultError(err1.Error())
|
||||
}
|
||||
if errResp.Code != 0 {
|
||||
return nil, fmt.Errorf(errResp.Msg)
|
||||
return nil, &CommonResultError{
|
||||
Code: errResp.Code,
|
||||
Msg: errResp.Msg,
|
||||
}
|
||||
}
|
||||
|
||||
// parse result
|
||||
@@ -314,13 +335,13 @@ func (h *LoginHelper) GetWebapiNewToken(ticketId, userId, oldAccessToken string)
|
||||
r.Data = &LoginTokenResult{}
|
||||
if err2 := json.Unmarshal(body, r); err2 != nil {
|
||||
logger.Verboseln("parse web token result json error ", err2)
|
||||
return nil, err2
|
||||
return nil, NewCommonResultError(err2.Error())
|
||||
}
|
||||
return r.Data.(*LoginTokenResult), nil
|
||||
}
|
||||
|
||||
// GetOpenapiNewToken 获取Openapi Token
|
||||
func (h *LoginHelper) GetOpenapiNewToken(ticketId, userId, oldAccessToken string) (*LoginTokenResult, error) {
|
||||
func (h *LoginHelper) GetOpenapiNewToken(ticketId, userId, oldAccessToken string) (*LoginTokenResult, *CommonResultError) {
|
||||
fullUrl := strings.Builder{}
|
||||
fmt.Fprintf(&fullUrl, "%s/auth/tickstep/aliyunpan/token/openapi/%s/refresh?userId=%s",
|
||||
h.webHost, ticketId, userId)
|
||||
@@ -338,27 +359,30 @@ func (h *LoginHelper) GetOpenapiNewToken(ticketId, userId, oldAccessToken string
|
||||
body, err := client.Fetch("GET", fullUrl.String(), nil, header)
|
||||
if err != nil {
|
||||
logger.Verboseln("get openapi token result error ", err)
|
||||
return nil, err
|
||||
return nil, NewCommonResultError(err.Error())
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
return nil, NewCommonResultError(err1.Error())
|
||||
}
|
||||
if commonResult.Code != 0 {
|
||||
return nil, fmt.Errorf(commonResult.Msg)
|
||||
return nil, commonResult
|
||||
}
|
||||
|
||||
// 解析结果
|
||||
errResp := &LoginHttpResult{}
|
||||
if err1 := json.Unmarshal(body, errResp); err1 != nil {
|
||||
logger.Verboseln("parse result json error ", err1)
|
||||
return nil, err1
|
||||
return nil, NewCommonResultError(err1.Error())
|
||||
}
|
||||
if errResp.Code != 0 {
|
||||
return nil, fmt.Errorf(errResp.Msg)
|
||||
return nil, &CommonResultError{
|
||||
Code: errResp.Code,
|
||||
Msg: errResp.Msg,
|
||||
}
|
||||
}
|
||||
|
||||
// parse result
|
||||
@@ -366,7 +390,7 @@ func (h *LoginHelper) GetOpenapiNewToken(ticketId, userId, oldAccessToken string
|
||||
r.Data = &LoginTokenResult{}
|
||||
if err2 := json.Unmarshal(body, r); err2 != nil {
|
||||
logger.Verboseln("parse openapi token result json error ", err2)
|
||||
return nil, err2
|
||||
return nil, NewCommonResultError(err2.Error())
|
||||
}
|
||||
return r.Data.(*LoginTokenResult), nil
|
||||
}
|
||||
@@ -393,7 +417,7 @@ func (h *LoginHelper) GetLoginToken(ticketId string) (*CommonTokenEntity, error)
|
||||
}
|
||||
|
||||
// 通用接口错误
|
||||
commonResult := &respCommonResult{}
|
||||
commonResult := &CommonResultError{}
|
||||
if err1 := json.Unmarshal(body, commonResult); err1 != nil {
|
||||
logger.Verboseln("parse openapi result json error ", err1)
|
||||
return nil, err1
|
||||
|
||||
Reference in New Issue
Block a user