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

求助:Spotify API POST请求失败及401未授权问题排查

解决Spotify PKCE认证400及获取Top艺术家401错误

核心问题分析

  1. POST请求400错误:大概率是code_challenge生成不符合Spotify的PKCE规范,或者重定向URI与后台配置不一致。
  2. GET请求401错误:redirectToken是异步函数,直接将其返回值作为token会导致Authorization头无效(实际是Bearer [object Promise]),且未等待token获取完成就发起请求。

第一步:修复PKCE流程(解决400错误)

首先确保generateRandomString和generateCodeChallenge函数完全符合Spotify要求:

  • code_verifier必须是43-128位的ASCII字符,仅包含a-z, A-Z, 0-9, -, ., _, ~
  • code_challenge是code_verifier的SHA-256哈希值,再经过base64url编码(去掉末尾的=,替换+为-,/为_)

添加正确的辅助函数:

function generateRandomString(length) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
  let result = '';
  const array = new Uint32Array(length);
  window.crypto.getRandomValues(array);
  for (let i = 0; i < length; i++) {
    result += chars[array[i] % chars.length];
  }
  return result;
}

async function generateCodeChallenge(codeVerifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(codeVerifier);
  const digest = await window.crypto.subtle.digest('SHA-256', data);
  // 转换为base64url格式
  return btoa(String.fromCharCode(...new Uint8Array(digest)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

同时确认:

  • Spotify开发者后台的重定向URI与代码中的redirectUri完全一致(包括http://127.0.0.1:5500/index.html的协议、端口、路径)
  • 每次认证流程中,code只能使用一次,避免重复提交

第二步:修复异步调用问题(解决401错误)

redirectToken是异步函数,需要返回Promise以便后续等待token获取完成;getTopArtists需要在拿到有效token后再发起请求。

修正后的redirectToken函数:

function redirectToken() {
  return new Promise((resolve, reject) => {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get('code');
    if (!code) {
      reject(new Error('未获取到授权code'));
      return;
    }
    
    const codeVerifier = localStorage.getItem('code-verifier');
    const redirectUri = 'http://127.0.0.1:5500/index.html';
    const clientId = "f101df3a42484b9e9aa1d1aa34fa5770";
    
    const body = new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: redirectUri,
      client_id: clientId,
      code_verifier: codeVerifier
    });
    
    fetch('https://accounts.spotify.com/api/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: body
    })
    .then(response => {
      if (!response.ok) {
        throw new Error('HTTP状态码: ' + response.status);
      }
      return response.json();
    })
    .then(data => {
      localStorage.setItem('access-token', data.access_token);
      resolve(data.access_token); // 返回token供后续使用
    })
    .catch(error => {
      console.error('获取token失败:', error);
      reject(error);
    });
  });
}

修正后的getTopArtists函数:

async function getTopArtists() {
  // 优先从localStorage取token,没有则调用redirectToken获取
  let accessToken = localStorage.getItem('access-token');
  if (!accessToken) {
    try {
      accessToken = await redirectToken();
    } catch (err) {
      console.error('无法获取有效token:', err);
      return;
    }
  }

  const url = "https://api.spotify.com/v1/me/top/artists?limit=3&offset=0&time_range=short_term";
  // 注意:offset=3会跳过前3个,要获取TOP3应该设为offset=0
  const xhr = new XMLHttpRequest();
  
  xhr.open("GET", url);
  xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
  
  xhr.onload = function() {
    if (xhr.status === 200) {
      const data = JSON.parse(xhr.responseText);
      console.log('TOP3艺术家:', data.items);
    } else {
      console.error('请求失败,状态码:', xhr.status);
      // 如果token过期,可触发重新认证
      if (xhr.status === 401) {
        localStorage.removeItem('access-token');
        authenticate();
      }
    }
  };
  
  xhr.onerror = function() {
    console.error('网络请求错误');
  };
  
  xhr.send();
}

调用流程说明

  1. 用户点击认证按钮触发authenticate(),跳转至Spotify授权页
  2. 授权完成后重定向回页面,调用redirectToken()获取并存储token
  3. 调用getTopArtists()时,会自动获取token并发起请求

额外提示:你的getTopArtists中offset=3会跳过前3个艺术家,若要获取真正的TOP3,需改为offset=0。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:42:03