第二次获取Spotify Refresh Token时出现invalid_grant错误的问题排查
问题分析与解决方案
你的核心问题出在刷新令牌的更新逻辑错误,以及对Spotify令牌机制的理解偏差,下面一步步拆解:
1. 错误根源:误用Access Token作为Refresh Token
看你的get_refresh_token方法里的这行代码:
self.current_refresh_token = token_request_json["access_token"]
这完全搞错了令牌的作用!Spotify的refresh_token是用来获取新access_token的长期凭证,而access_token是短期的API请求凭证。第一次刷新令牌时,Spotify的响应里不会返回新的refresh_token(除非应用权限或配置有特殊要求),所以你不能把返回的access_token赋值给current_refresh_token——这直接导致下一次刷新时,你用无效的access_token当作refresh_token去请求,自然触发invalid_grant错误。
2. 正确的Refresh Token处理逻辑
Spotify的refresh_token默认是长期有效的(只要用户没有撤销你的应用权限),所以你只需要在首次获取令牌时保存好初始的refresh_token,后续刷新时复用这个refresh_token即可。只有当刷新响应里明确返回了新的refresh_token字段时,才需要替换原有值。
3. 代码修正
修复get_refresh_token方法
把错误的赋值语句调整为仅在响应包含新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 # 返回None避免后续代码报错
优化循环中的令牌刷新逻辑
你的代码每次循环都刷新令牌,这完全没必要——access_token的有效期是3600秒,建议在令牌即将过期时再刷新:
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 next_url = "" total = 1000000 # 记录令牌过期时间(当前时间+有效期) token_expires_at = time.time() + token["expires_in"] while offset <= total or next_url is not None: # 提前60秒刷新令牌,避免请求时令牌过期 if time.time() >= token_expires_at - 60: new_token = token_manager.get_refresh_token() if new_token: token = new_token token_expires_at = 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 ) if tracks_request.status_code != 200: print(f"Track request failed: {tracks_request.status_code} - {tracks_request.text}") break tracks_json_response = tracks_request.json() # 用requests内置json方法更简洁 offset += limit total = tracks_json_response["total"] next_url = tracks_json_response["next"] # 这里可以添加曲目数据处理逻辑,比如打印或保存 # for item in tracks_json_response["items"]: # print(item["track"]["name"])
4. 额外注意事项
- 确保你的授权请求包含
offline_accessscope,这是获取refresh_token的必要条件(从你的输出看已经满足)。 - 不要硬编码密钥和授权码到代码中,建议用环境变量管理,避免敏感信息泄露。
- 当
get_refresh_token返回None时,要做容错处理,比如终止流程或提示用户重新授权。
内容的提问来源于stack exchange,提问作者telexon
相关产品推荐
相关产品推荐

