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

React中使用Spotify API获取数据时刷新或更新状态出现400/401错误

解决Spotify API刷新/状态更新时400/401错误的方案

核心原因分析

  1. Token过期或无效:首次请求用的是有效token,但刷新页面后从缓存读取的token已过期;状态更新触发重复请求时,token可能已失效。
  2. 竞态条件:组件重新渲染时发起重复请求,旧请求的token已失效却仍在执行。
  3. 冗余配置冲突:axios.get已默认使用GET方法,额外设置method: 'GET'可能引发不必要的配置问题。

具体解决步骤

1. 先验证Token有效性

请求前主动检查token是否可用,避免无效请求:

const validateToken = async (token: string) => {
  try {
    await axios.get('https://api.spotify.com/v1/me', {
      headers: { Authorization: `Bearer ${token}` }
    });
    return true;
  } catch {
    return false;
  }
};

在调用时先验证再请求:

useEffect(() => {
  if (!token) return;

  const fetchData = async () => {
    const isValid = await validateToken(token);
    if (!isValid) {
      console.log('Token无效,需重新获取');
      // 这里可触发重新登录或token刷新逻辑
      return;
    }
    const data = await fetchFromAPI('browse/new-releases', token);
    setAlbums(data.albums.items.map(item => item.id));
  };

  fetchData();
}, [token]);

2. 实现Token自动刷新逻辑

Spotify的access token默认1小时过期,用refresh token获取新token(注意:client_id需通过后端代理,避免前端暴露敏感信息):

const refreshAccessToken = async (refreshToken: string, clientId: string) => {
  const response = await axios.post(
    'https://accounts.spotify.com/api/token',
    new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: clientId
    })
  );
  return {
    accessToken: response.data.access_token,
    expiresIn: response.data.expires_in
  };
};

修改fetchFromAPI添加错误重试:

export const fetchFromAPI = async (url: string, token: string, refreshToken?: string, clientId?: string) => {
  try {
    const { data } = await axios.get(`${BASE_URL}/${url}`, {
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`
      }
    });
    return data;
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401 && refreshToken && clientId) {
      // 刷新token
      const { accessToken } = await refreshAccessToken(refreshToken, clientId);
      // 更新Context中的token,比如调用setToken(accessToken)
      // 重试请求
      const { data } = await axios.get(`${BASE_URL}/${url}`, {
        headers: { Authorization: `Bearer ${accessToken}` }
      });
      return data;
    }
    throw error;
  }
};

3. 避免竞态条件与重复请求

用AbortController取消未完成的请求,防止旧请求返回无效数据:

useEffect(() => {
  if (!token) return;

  const controller = new AbortController();
  const signal = controller.signal;

  const fetchData = async () => {
    try {
      const data = await axios.get(`${BASE_URL}/browse/new-releases`, {
        headers: { Authorization: `Bearer ${token}` },
        signal
      });
      setAlbums(data.albums.items.map(item => item.id));
    } catch (err) {
      if (axios.isAxiosError(err) && err.code === 'ERR_CANCELED') return;
      console.error('请求失败:', err);
    }
  };

  fetchData();

  // 组件卸载或依赖变化时取消请求
  return () => controller.abort();
}, [token]);

4. 清理冗余配置

去掉axios.get中多余的method: 'GET'配置,避免潜在冲突:

// 修改后的fetchFromAPI请求部分
const { data } = await axios.get(`${BASE_URL}/${url}`, {
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:35:37