You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

第二次获取Spotify Refresh Token时出现错误的问题排查

问题分析与修复方案

你的核心问题出在refresh token的处理逻辑错误,以及对Spotify令牌刷新机制的误解,下面一步步拆解问题并给出修复方案:

1. 致命错误:错误覆盖Refresh Token

看你的get_refresh_token方法里的这行代码:

self.current_refresh_token = token_request_json["access_token"]

你把新获取的access_token赋值给了current_refresh_token,这直接导致第二次刷新令牌时,你用一个无效的access token当作refresh token去请求,自然会返回invalid_grant错误。

2. 对Spotify Refresh Token机制的误解

Spotify并不是每次刷新令牌都会返回新的refresh token:

  • 只有当你首次授权请求时包含offline_access scope,才会得到初始的refresh token。
  • 后续的刷新请求不会默认返回新的refresh token,只有在特定场景下(比如原refresh token即将过期、账号安全状态变化)才会返回新的。

所以正确的做法是:只在刷新响应中存在refresh_token字段时,才更新你的current_refresh_token,否则保留原来的refresh token继续使用。

3. 额外问题:不必要的频繁令牌刷新

你的循环里每次请求用户曲目时都调用get_refresh_token,这完全没有必要。Spotify的access token有效期是3600秒(1小时),你应该在access token快要过期时,或者收到401 Unauthorized响应时再去刷新令牌,而不是每次请求都刷新。

修复后的代码示例

修正TokenManager的get_refresh_token方法

def get_refresh_token(self):
    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = {
        "client_id": "<client-id>",
        "client_secret": "<client-secret>",
        "refresh_token": self.current_refresh_token,
        "grant_type": "refresh_token"
    }
    token_request = requests.post(
        url="https://accounts.spotify.com/api/token",
        data=data,
        headers=headers
    )
    if token_request.status_code == 200:
        token_request_json = json.loads(token_request.text)
        print(token_request_json)
        # 仅当响应包含新的refresh_token时才更新
        if "refresh_token" in token_request_json:
            self.current_refresh_token = token_request_json["refresh_token"]
        return token_request_json
    else:
        print(token_request.status_code)
        print(token_request.text)
        return None

修正get_tracks函数的令牌刷新逻辑

def get_tracks():
    token_manager = TokenManager()
    token = token_manager.get_first_spotify_token()
    if not token:
        print("Failed to get initial token")
        return
    
    limit = 50
    offset = 0
    total = 0
    # 记录access token的过期时间
    token_expiry = time.time() + token["expires_in"]
    
    while True:
        # 检查access token是否即将过期,提前刷新
        if time.time() >= token_expiry - 60:  # 提前60秒刷新
            new_token = token_manager.get_refresh_token()
            if new_token:
                token = new_token
                token_expiry = time.time() + token["expires_in"]
            else:
                print("Failed to refresh token")
                break
        
        params = {
            "limit": limit,
            "offset": offset
        }
        headers = {
            "Authorization": f"{token['token_type']} {token['access_token']}"
        }
        tracks_request = requests.get(
            url="https://api.spotify.com/v1/me/tracks",
            headers=headers,
            params=params
        )
        
        # 处理401错误(access token已过期)
        if tracks_request.status_code == 401:
            new_token = token_manager.get_refresh_token()
            if new_token:
                token = new_token
                token_expiry = time.time() + token["expires_in"]
                # 重新发送请求
                tracks_request = requests.get(
                    url="https://api.spotify.com/v1/me/tracks",
                    headers={"Authorization": f"{token['token_type']} {token['access_token']}"},
                    params=params
                )
            else:
                print("Failed to refresh token after 401")
                break
        
        if tracks_request.status_code != 200:
            print(f"Track request failed: {tracks_request.status_code}")
            print(tracks_request.text)
            break
        
        tracks_json_response = tracks_request.json()
        total = tracks_json_response["total"]
        offset += limit
        
        # 在这里处理获取到的曲目数据,比如打印或者保存
        print(f"Fetched {len(tracks_json_response['items'])} tracks")
        
        # 终止循环条件
        if offset >= total:
            break

最后确认

确保你首次授权时的scope包含offline_access,否则你根本无法获取到refresh token,后续的刷新操作也会失败。

内容的提问来源于stack exchange,提问作者telexon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 09:22:33