Django+Supabase对接Spotify API遇401/403错误求助
Django + Supabase 实现Spotify OAuth登录后调用API报错问题排查与解决
问题背景
开发Django应用时,通过Supabase实现Spotify OAuth登录,调用Spotify API获取用户热门曲目时,先后遇到401、403错误,以及Uncaught (in promise) SyntaxError: Unexpected end of JSON input解析错误。相关代码如下:
认证视图代码
def spotify_auth(request): # Redirect the user to Supabase's OAuth authentication endpoint data = supabase_client.auth.sign_in_with_oauth({ "provider": 'spotify', "scopes": 'user-top-read', "redirectTo": "http://127.0.0.1:8000//callback/", }) auth_url = data.url return redirect(auth_url)
前端存储token代码
// Get the fragment URL from the current URL const fragmentUrl = window.location.hash; // Parse the fragment URL to extract key-value pairs const urlParams = new URLSearchParams(fragmentUrl.substring(1)); // Extract and save each piece of data const access_token = urlParams.get('access_token'); // Save the extracted data to localStorage (or sessionStorage if needed) localStorage.setItem('access_token', access_token);
前端调用Spotify API代码
<script> const access_token = localStorage.getItem('access_token'); console.log("access token:",access_token) const getTopTracks = async () => { const url = new URL('https://api.spotify.com/v1/me/top/tracks'); url.searchParams.append('time_range', 'short-term'); url.searchParams.append('limit', '20'); const response = await fetch(url,{ method:'GET', headers: { 'Authorization': 'Bearer ' + access_token }, }); const data = await response.json(); console.log(data) } getTopTracks(); </script>
核心错误点
你从URL hash中获取的access_token是Supabase自身的认证JWT令牌,并非Spotify官方API的访问令牌,直接用它调用Spotify API必然会触发权限错误。此外还有以下细节问题:
- 回调地址存在双斜杠
//,可能导致URL解析异常 - 前端未处理API响应错误,非JSON响应直接解析会触发语法错误
解决步骤
1. 修正回调地址格式
将视图中的redirectTo从http://127.0.0.1:8000//callback/改为http://127.0.0.1:8000/callback/,确保URL格式正确,避免解析异常。
2. 后端获取Spotify官方访问令牌
不要在前端从hash提取token,而是在Django的callback视图中通过Supabase获取用户关联的Spotify provider令牌:
def spotify_callback(request): # 完成Supabase OAuth回调会话处理 supabase_client.auth.get_session_from_url(request.build_absolute_uri()) # 获取当前用户关联的Spotify provider令牌 provider_token_data = supabase_client.auth.get_user_provider_access_token('spotify') spotify_access_token = provider_token_data['access_token'] # 将令牌存入session,供后续请求使用 request.session['spotify_access_token'] = spotify_access_token # 重定向到热门曲目页面 return redirect('/top-tracks/')
3. 后端代理Spotify API请求(推荐方案)
直接在前端暴露Spotify令牌存在安全风险,建议通过后端代理API请求:
def top_tracks(request): spotify_access_token = request.session.get('spotify_access_token') if not spotify_access_token: return redirect('spotify_auth') # 调用Spotify API获取热门曲目 import requests api_url = 'https://api.spotify.com/v1/me/top/tracks' params = { 'time_range': 'short-term', 'limit': 20 } headers = { 'Authorization': f'Bearer {spotify_access_token}' } response = requests.get(api_url, params=params, headers=headers) if response.status_code != 200: # 可添加令牌过期刷新逻辑 return HttpResponse('获取热门曲目失败', status=response.status_code) tracks_data = response.json() return render(request, 'top_tracks.html', {'tracks': tracks_data})
4. 前端错误处理优化(若坚持前端调用)
如果必须前端调用API,需确保获取的是Spotify官方令牌,并添加错误处理:
<script> const getTopTracks = async () => { // 从后端获取正确的Spotify令牌(可通过接口或模板变量传递) const spotify_access_token = localStorage.getItem('spotify_access_token'); if (!spotify_access_token) { window.location.href = '/spotify-auth/'; return; } const url = new URL('https://api.spotify.com/v1/me/top/tracks'); url.searchParams.append('time_range', 'short-term'); url.searchParams.append('limit', '20'); try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer ' + spotify_access_token }, }); if (!response.ok) { console.error('API请求失败:', response.status, response.statusText); // 处理令牌过期等情况,比如跳转重新授权 return; } const data = await response.json(); console.log(data); } catch (error) { console.error('请求出错:', error); } } getTopTracks(); </script>
5. 确认第三方配置正确性
- 在Spotify开发者后台,确保回调地址与
redirectTo完全一致(单斜杠) - 在Supabase控制台的Spotify OAuth配置中,确认已添加
user-top-read权限范围 - 检查Supabase的项目URL和API密钥配置是否正确
内容的提问来源于stack exchange,提问作者KevinL
相关产品推荐
相关产品推荐

