第二次获取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_accessscope,才会得到初始的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
相关产品推荐
相关产品推荐

