package services import ( "context" "encoding/json" "fmt" "go-policy-service/models" "go-policy-service/structs" "go-policy-service/utils" "log" "time" "github.com/go-redis/redis/v8" ) type TokenManager struct { rdb *redis.Client hgConfig *models.HgConfig httpClient utils.HTTPClient // 自己请求 token apiUrl string // 自己请求 token 的接口 } // 修复构造函数参数声明 func NewTokenManager( rdb *redis.Client, hgConfig *models.HgConfig, httpClient utils.HTTPClient, // 明确参数类型 apiUrl string, // 添加类型声明 ) *TokenManager { return &TokenManager{ rdb: rdb, hgConfig: hgConfig, httpClient: httpClient, apiUrl: apiUrl, } } func (t *TokenManager) GetAccessToken() (string, error) { tokenKey := fmt.Sprintf("60s-hgapi-%s", t.hgConfig.Account) ctx := context.Background() // 尝试从 Redis 获取现有 token token, err := t.rdb.Get(ctx, tokenKey).Result() if err == nil { return token, nil } // 重试机制 const maxRetries = 3 for i := 0; i < maxRetries; i++ { tokenData, err := t.requestToken() if err == nil { expireTimestamp := utils.StringToTimestamp(tokenData.ExpireTime, "2006-01-02 15:04:05") // 提前半小时失效 durationSeconds := expireTimestamp - time.Now().Unix() // 确保最小有效期为0秒 if durationSeconds < 0 { durationSeconds = 0 } // 成功获取 token 后存入 Redis if setErr := t.rdb.SetEX(ctx, tokenKey, tokenData.AccessToken, time.Duration(durationSeconds)*time.Second).Err(); setErr != nil { log.Printf("Failed to set token in Redis: %v", setErr) } return tokenData.AccessToken, nil } log.Printf("获取hgApi token失败,剩余重试次数: %d, 错误: %v", maxRetries-i-1, err) if i < maxRetries-1 { time.Sleep(1 * time.Second) } } log.Println("hgApi token获取彻底失败,请检查接口状态") return "", fmt.Errorf("failed to get token after %d attempts", maxRetries) } func (t *TokenManager) requestToken() (structs.TokenData, error) { url := fmt.Sprintf("%s/gateway/oauth/token?grant_type=client_credentials&client_id=%s&client_secret=%s", t.apiUrl, t.hgConfig.Account, t.hgConfig.Password) respBytes, err := t.httpClient.RequestJSON(context.Background(), "GET", url, nil) if err != nil { return structs.TokenData{}, fmt.Errorf("HTTP请求失败: %w", err) } var tokenResp structs.TokenResponse if err := json.Unmarshal(respBytes, &tokenResp); err != nil { return structs.TokenData{}, fmt.Errorf("JSON解析失败: %w", err) } if !tokenResp.Success || tokenResp.Data.AccessToken == "" { return structs.TokenData{}, fmt.Errorf("接口返回无效响应") } return tokenResp.Data, nil }