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

Spotify API报错求助:仅支持有效Bearer认证及404问题

问题分析与修复方案

核心错误点

  1. Authorization头无效:getTokenPub()返回的是Promise对象而非实际token字符串,直接拼接后会变成Bearer [object Promise],这就是你收到"Only Valid bearer authentication supported"错误的根本原因。
  2. 异步流程混乱:获取token是异步操作,必须等待token返回后再发起搜索请求,你的代码没有处理异步执行顺序。
  3. 潜在编码问题:如果token请求出现404,大概率是clientId/clientSecret包含特殊字符,直接用btoa编码会失败。
  4. 密钥暴露风险:把Spotify的Client ID和Client Secret放在前端完全不安全,任何人都能窃取滥用,必须移到后端代理。

修复后的代码

// 警告:生产环境绝对不能把clientId和clientSecret写在前端!
const clientId = '你的Client ID';
const clientSecret = '你的Client Secret';

const _getToken = async () => {
    try {
        // 对密钥做编码处理,避免特殊字符导致btoa失败
        const encodedCredentials = btoa(`${encodeURIComponent(clientId)}:${encodeURIComponent(clientSecret)}`);
        const result = await fetch('https://accounts.spotify.com/api/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Authorization': `Basic ${encodedCredentials}`
            },
            body: 'grant_type=client_credentials'
        });

        if (!result.ok) throw new Error(`Token请求失败:${result.status}`);
        const data = await result.json();
        return data.access_token;
    } catch (error) {
        console.error('获取Token出错:', error);
        throw error;
    }
};

// 按正确顺序执行异步操作
const fetchSpotifyPlaylists = async () => {
    try {
        const token = await _getToken();
        // 修复搜索参数的双重编码问题:%2520改为%20
        const searchResult = await fetch('https://api.spotify.com/v1/search?q=similar%20artists%20to%20frank%20ocean&type=playlist&limit=5', {
            method: 'GET',
            headers: { 'Authorization': `Bearer ${token}` }
        });

        if (!searchResult.ok) throw new Error(`搜索请求失败:${searchResult.status}`);
        const data = await searchResult.json();
        const descContainer = document.querySelector('.desc');
        
        // 清空容器避免重复渲染
        descContainer.innerHTML = '';

        data.playlists.items.forEach(playlist => {
            // 兼容无描述/无图片的情况,避免渲染崩溃
            const playlistDesc = playlist.description || '无描述';
            const playlistImgUrl = playlist.images[0]?.url || '';

            const markup = `
                <li><strong>名称:</strong>${playlist.name}</li>
                <li><strong>描述:</strong>${playlistDesc}</li>
                <input type="button" onclick="location.href='${playlist.external_urls.spotify}'" value="Listen" />
                ${playlistImgUrl ? `<img width="100" height="100" style="border-radius: 50px" src="${playlistImgUrl}" alt="${playlist.name}封面">` : ''}
                <hr>
            `;
            descContainer.insertAdjacentHTML('beforeend', markup);
        });

        console.log('搜索结果:', data);
    } catch (error) {
        console.error('整体流程出错:', error);
    }
};

// 触发请求
fetchSpotifyPlaylists();

关键优化说明

  • 修复异步流程:用async/await确保先拿到token再发起搜索请求
  • 增强错误处理:添加HTTP状态码检查,避免静默失败
  • 兼容边界情况:处理播放列表无描述、无图片的场景
  • 修正编码问题:修复搜索参数的双重编码,对密钥做URI编码后再用btoa处理
  • 代码可读性:变量名更贴合语义,模板字符串直接写HTML无需转义

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

相关产品推荐
方舟 Agent Plan

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

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