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
相关产品推荐
相关产品推荐

