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

AngularJS中表单提交时过期Token的表单值保留方案问询

在AngularJS中处理Token过期时的表单暂存与重试方案

Hey,这个场景我在AngularJS项目里处理过好多次,给你一套完整的解决方案,亲测靠谱~核心思路是用HTTP拦截器统一拦截请求,Token过期时暂存请求(包括表单数据),刷新Token后自动重试,同时配合表单层面的临时存储确保数据不丢失。

1. 先搞定Token的存储与过期时间管理

首先,登录成功后要把Token和它的过期时间一起存在本地(比如localStorage),方便后续判断是否过期:

// 登录成功后的处理逻辑(比如在authService里)
function handleLoginSuccess(response) {
  const token = response.data.token;
  const refreshToken = response.data.refreshToken; // 刷新Token用,后端要支持
  const expiresAt = Date.now() + 3600 * 1000; // 1小时后过期,转成毫秒

  localStorage.setItem('authToken', token);
  localStorage.setItem('refreshToken', refreshToken);
  localStorage.setItem('tokenExpiresAt', expiresAt.toString());
}

2. 核心:创建HTTP拦截器处理Token过期

AngularJS的$httpProvider.interceptors是处理这类全局请求逻辑的神器,我们可以在这里做三件事:

  • 请求发送前检查Token是否过期,未过期则添加到请求头
  • 响应返回401(Token过期的常见状态码)时,触发Token刷新
  • 暂存所有失败的请求,刷新Token后批量重试
angular.module('yourApp')
  .factory('authInterceptor', ['$q', '$injector', '$window', function($q, $injector, $window) {
    let isRefreshingToken = false; // 防止重复触发Token刷新
    let pendingRequests = []; // 暂存等待重试的请求队列

    // 辅助函数:判断Token是否过期
    function isTokenExpired() {
      const expiresAt = parseInt($window.localStorage.getItem('tokenExpiresAt'), 10);
      return !expiresAt || Date.now() > expiresAt;
    }

    return {
      // 请求拦截:添加Token到请求头
      request: function(config) {
        const token = $window.localStorage.getItem('authToken');
        if (token && !isTokenExpired()) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },

      // 响应错误拦截:处理Token过期
      responseError: function(response) {
        const $http = $injector.get('$http');
        const authService = $injector.get('authService');

        // 只处理401未授权(Token过期/无效)的情况
        if (response.status === 401) {
          if (!isRefreshingToken) {
            isRefreshingToken = true;

            // 调用刷新Token的接口
            return authService.refreshToken()
              .then(function(newTokenData) {
                // 更新本地存储的Token和过期时间
                $window.localStorage.setItem('authToken', newTokenData.token);
                $window.localStorage.setItem('tokenExpiresAt', (Date.now() + 3600 * 1000).toString());

                // 重试所有暂存的请求
                pendingRequests.forEach(function(deferred) {
                  deferred.resolve();
                });
                pendingRequests = [];

                // 重试当前失败的表单提交请求
                return $http(response.config);
              })
              .catch(function(error) {
                // 刷新Token失败,清空队列并引导用户登录
                pendingRequests.forEach(function(deferred) {
                  deferred.reject(error);
                });
                pendingRequests = [];
                $window.location.href = '/login'; // 跳转到登录页
                return $q.reject(error);
              })
              .finally(function() {
                isRefreshingToken = false;
              });
          } else {
            // 如果正在刷新Token,把当前请求加入队列等待
            const deferred = $q.defer();
            pendingRequests.push(deferred);
            return deferred.promise.then(function() {
              return $http(response.config);
            });
          }
        }

        // 其他错误直接返回拒绝
        return $q.reject(response);
      }
    };
  }])
  // 注册拦截器
  .config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('authInterceptor');
  }]);

3. 表单层面的额外保障:暂存表单数据

上面的拦截器已经能自动处理请求重试,但为了防止页面意外刷新导致表单数据丢失,可以在表单提交前把数据临时存在sessionStorage里,提交成功后再清除:

angular.module('yourApp')
  .controller('FormSubmitController', ['$scope', '$http', '$window', function($scope, $http, $window) {
    // 初始化表单:先检查有没有暂存的表单数据(比如上次刷新Token时没提交完的)
    const savedFormData = $window.sessionStorage.getItem('pendingForm');
    if (savedFormData) {
      $scope.formData = JSON.parse(savedFormData);
      $window.sessionStorage.removeItem('pendingForm');
    } else {
      $scope.formData = {};
    }

    // 表单提交函数
    $scope.submitForm = function() {
      // 先暂存表单数据到sessionStorage
      $window.sessionStorage.setItem('pendingForm', JSON.stringify($scope.formData));

      $http.post('/api/your-form-endpoint', $scope.formData)
        .then(function(response) {
          // 提交成功,清除暂存的表单数据
          $window.sessionStorage.removeItem('pendingForm');
          // 处理成功逻辑:比如提示用户、清空表单
          alert('表单提交成功!');
          $scope.formData = {};
        })
        .catch(function(error) {
          // 处理其他错误(比如网络问题)
          if (error.status !== 401) {
            alert('提交失败,请稍后重试');
          }
        });
    };
  }]);

4. 封装刷新Token的服务

把刷新Token的逻辑单独抽成服务,代码更清晰易维护:

angular.module('yourApp')
  .factory('authService', ['$http', function($http) {
    return {
      refreshToken: function() {
        const refreshToken = localStorage.getItem('refreshToken');
        // 调用后端的刷新Token接口
        return $http.post('/api/refresh-token', { refreshToken: refreshToken })
          .then(function(response) {
            return response.data;
          });
      }
    };
  }]);

关键注意点

  • 避免重复刷新Token:用isRefreshingToken标志位控制,防止多个请求同时触发刷新
  • 请求队列管理:把所有失败的请求存在队列里,刷新Token后批量重试,避免用户重复提交
  • 表单数据安全:用sessionStorage暂存,页面关闭后自动清除,比localStorage更安全
  • 失败降级:刷新Token失败时,一定要清空队列并引导用户重新登录,避免无限循环

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:49:09