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

ReactJs环境下token过期自动调用token API及按需重渲染实现问题

实现token自动过期刷新+自动重渲染方案

现有代码问题梳理

  • 时间比较逻辑错误:用12小时制的时分秒字符串做比较,跨天场景会完全失效,应该用时间戳(毫秒级数值)做比较才准确
  • 仅在组件挂载时检查一次过期:没有持续监听token过期状态,没法实现到期自动触发刷新
  • setState异步坑:调用setState后直接取this.state拿不到最新值,存sessionStorage应该直接用接口返回的响应数据
  • 方法this指向丢失:类组件里自定义方法如果不用箭头函数或者手动bind,调用时this会指向undefined

完整实现代码

下面的实现会在token到期时自动触发刷新,state更新后会自动触发组件重渲染:

import React from 'react';
import axios from 'axios';
class ApiCall extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      token: '',
      expiry: 0 // 存13位毫秒级时间戳
    };
    this.refreshTimer = null; // 存定时器id,卸载时清除
  }

  // 用箭头函数固定this指向
  tokenApiCall = () => {
    axios
    .post(
        'https://api/v1/Getauthtoken',
      {
            username: 'xyz',
            client: 'XYZ', 
      }
    )
    .then((res) => {
      // 接口返回的expires_in一般是有效秒数,计算出过期时间戳
      const expiryTimestamp = Date.now() + res.expires_in * 1000;
      // 更新state,会自动触发重渲染
      this.setState({ 
        token: res.token, 
        expiry: expiryTimestamp
      });
      // 直接用接口返回的值存缓存,不要用this.state(setState是异步的)
      sessionStorage.setItem('tokenval', res.token);
      sessionStorage.setItem('tokenExp', expiryTimestamp);
      // 刷新后设置下一次到期自动刷新的定时器
      this.setRefreshTimer(expiryTimestamp);
    })
    .catch((error) => {
      console.log('Error message is ' + error);
    }); 
  }

  // 设置到期自动刷新定时器
  setRefreshTimer = (expiryTimestamp) => {
    // 先清除之前的定时器避免重复
    if (this.refreshTimer) clearTimeout(this.refreshTimer);
    // 计算还有多久过期,提前100ms刷新避免刚好到期时请求失效
    const delay = expiryTimestamp - Date.now() - 100;
    if (delay > 0) {
      this.refreshTimer = setTimeout(() => {
        this.tokenApiCall();
      }, delay);
    } else {
      // 已经过期直接刷新
      this.tokenApiCall();
    }
  }

  componentDidMount() {
    const localToken = sessionStorage.getItem('tokenval');
    const localExpiry = Number(sessionStorage.getItem('tokenExp'));
    if (!localToken || !localExpiry) {
      // 本地没有缓存直接请求新token
      this.tokenApiCall();
    } else {
      if (Date.now() > localExpiry) {
        // 已经过期直接刷新
        this.tokenApiCall();
      } else {
        // 本地token有效,更新state触发重渲染,同时设置定时器
        this.setState({
          token: localToken,
          expiry: localExpiry
        });
        this.setRefreshTimer(localExpiry);
      }
    }
  }

  // 组件卸载时清除定时器避免内存泄漏
  componentWillUnmount() {
    if (this.refreshTimer) clearTimeout(this.refreshTimer);
  }

  render() {
    // state里的token更新会自动触发render重渲染,需要用token的逻辑直接取this.state.token即可
    return <div>当前token:{this.state.token}</div>
  }
}

export default ApiCall;

额外优化建议

如果你的token是给全局接口请求用的,更推荐搭配axios请求拦截器实现:每次发送请求前先检查token是否过期,如果过期先暂停当前请求,刷新token后再继续发送请求,不需要轮询/定时器,性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:24:01