调用Spotify队列接口实现自动续播时遭遇502错误
问题背景
我想实现曲目播放结束后自动播放下一首的功能,尝试使用Spotify API的「Add Item to Playback Queue」接口,但遇到了502错误。已确认传入的uri、device_id参数无误,请求头中也添加了有效的accessToken,官方文档及社区中均无相关内容,求解决方法或其他添加曲目到播放队列的方式。
相关代码
WebPlayback.tsx
import { useEffect, useState } from 'react'; import Player from './pages/Player'; import { PlayerContext } from './PlayerContext'; import getTokens from './utils/functions/getTokens'; export interface IPlayerContext { player: Spotify.Player | null; deviceId: string; } function WebPlayback() { const [player, setPlayer] = useState<Spotify.Player | null>(null); const [deviceId, setDeviceId] = useState(''); useEffect(() => { const script = document.createElement('script'); script.src = 'https://sdk.scdn.co/spotify-player.js'; script.async = true; document.body.appendChild(script); window.onSpotifyWebPlaybackSDKReady = () => { const player = new window.Spotify.Player({ name: 'Mucketlist Player SDK', getOAuthToken: (cb) => { cb(getTokens()); }, volume: 0.5, }); setPlayer(player); player.addListener('ready', ({ device_id }) => { console.log('Ready with Device ID', device_id); setDeviceId(device_id); }); player.addListener('not_ready', ({ device_id }) => { console.log('Device ID has gone offline', device_id); }); player.connect(); }; }, []); return ( <PlayerContext.Provider value={{ player, deviceId }}> <Player /> </PlayerContext.Provider> ); } export default WebPlayback;
Player.tsx
function Player({ tracks }: PlayerState) { const playerState = useContext(PlayerContext); useEffect(() => { if (!playerState.deviceId) return; if (!(Array.isArray(tracks) && tracks.length === 0)) { addItemPlaybackQueue(); } }, [playerState.deviceId]); const addItemPlaybackQueue = async () => { const newQueue = 'spotify:track:4DmBVImaIhE3RyNvbtZTTz'; const response = await axios.post( `https://api.spotify.com/v1/me/player/queue?uri=${newQueue}&device_id=${playerState.deviceId}`, {}, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getTokens()}`, }, } ); console.log(response); }; return ( <PlayerWrap> <button onClick={isPlay ? onPause : onPlay}> {isPlay ? 'pause' : 'play'} </button> <div> {!isShowVolumeMixer ? null : ( <input type="range" min="0" max="1" step="0.1" value={currentVolume} onChange={handleVolume} /> )} <VolumeButton onClick={() => setIsShowVolumeMixer((prevState) => !prevState)} > Volume </VolumeButton> </div> <button onClick={onPreviousTrack}>previousTrack</button> <button onClick={onNextTrack}>nextTrack</button> <button onClick={getState}>getState</button> </PlayerWrap> ); } const mapStateToProps = (state: PlayerState) => { return { tracks: state.tracks, }; }; export default connect(mapStateToProps)(Player);
遇到的错误
POST https://api.spotify.com/v1/me/player/queue?uri=spotify:track:4DmBVImaIhE3RyNvbtZTTz&device_id=94867997ce023ed6effe8662c5ca6236ab30963a 502 Uncaught (in promise) AxiosError {message: 'Request failed with status code 502', name: 'AxiosError', code: 'ERR_BAD_RESPONSE', config: {…}, request: XMLHttpRequest, …}
解决办法
确认设备活跃状态
调用GET /me/player/devices接口检查目标设备是否处于active状态。Web Playback SDK的设备需要确保已成功连接,且未被其他Spotify客户端抢占播放控制权。调整请求触发时机
当前在deviceId变更时立即调用接口,可能设备尚未完全初始化。建议监听Web Playback SDK的player_state_changed事件,在当前曲目播放接近结束时(比如剩余时间小于5秒)再执行添加队列操作,确保设备处于稳定播放状态。使用Web Playback SDK内置队列方法
无需调用REST API,直接用SDK提供的setQueue方法添加曲目到队列,示例代码:const addToQueueViaSDK = () => { if (!playerState.player) return; playerState.player.setQueue({ uris: ['spotify:track:4DmBVImaIhE3RyNvbtZTTz'] }) .then(() => console.log('曲目已加入队列')) .catch(err => console.error('添加失败:', err)); };这个方法更贴合Web Playback场景,避免REST API的网络异常问题。
验证权限范围
确认accessToken已包含user-modify-playback-state权限,这是操作播放队列的必要权限。若授权时未添加该权限,即使token有效也可能导致服务端异常。添加临时重试逻辑
502属于网关级临时错误,可添加简单的重试机制,比如请求失败后间隔1-2秒重试,最多重试2-3次:const addItemPlaybackQueue = async (retryCount = 0) => { const maxRetries = 2; try { const newQueue = 'spotify:track:4DmBVImaIhE3RyNvbtZTTz'; const response = await axios.post( `https://api.spotify.com/v1/me/player/queue?uri=${newQueue}&device_id=${playerState.deviceId}`, {}, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getTokens()}` } } ); console.log(response); } catch (err) { if (retryCount < maxRetries && err.response?.status === 502) { setTimeout(() => addItemPlaybackQueue(retryCount + 1), 1500); } else { console.error('最终请求失败:', err); } } };
内容的提问来源于stack exchange,提问作者pickle23

