请求错误时重试Post/Get并执行原回调,登录过期无跳转重登咨询
我来帮你搞定这个AngularJS里的认证过期重登问题,刚好之前做过类似的业务场景,给你一套完整可落地的实现方案:
解决方案:AngularJS请求认证过期无跳转重登并自动重试
核心思路是利用AngularJS的$http拦截器全局捕获认证失败的响应,弹出登录模态框让用户重新登录,登录成功后自动重试原本的请求,同时完全保留原请求的success/error回调逻辑,不会丢失用户当前的操作状态。
步骤1:创建HTTP响应拦截器
这个拦截器会监听所有$http请求的错误响应,当检测到服务器返回401(身份验证过期)时,暂停后续请求并触发登录流程:
angular.module('yourApp').factory('authInterceptor', ['$q', '$injector', '$modal', function($q, $injector, $modal) { // 用来存储等待重试的请求队列 var deferredQueue = []; // 标记是否正在处理登录流程,避免重复弹出登录框 var isHandlingLogin = false; return { responseError: function(response) { // 只处理未标记为重试请求的401错误 if (response.status === 401 && !response.config.__isRetryRequest) { var deferred = $q.defer(); deferredQueue.push(deferred); // 首次触发登录流程时弹出模态框 if (!isHandlingLogin) { isHandlingLogin = true; var loginModal = $modal.open({ templateUrl: 'login-modal.html', controller: 'LoginModalCtrl', backdrop: 'static' // 禁止点击背景关闭模态框 }); // 登录成功后的处理 loginModal.result.then(function() { isHandlingLogin = false; // 遍历队列,重试所有等待的请求 angular.forEach(deferredQueue, function(deferred) { // 复制原请求配置并标记为重试请求,防止无限循环 var retryConfig = angular.copy(response.config); retryConfig.__isRetryRequest = true; // 重新发起请求并resolve原deferred $injector.get('$http')(retryConfig).then(deferred.resolve, deferred.reject); }); deferredQueue = []; }, function() { // 用户取消登录,拒绝所有排队请求 isHandlingLogin = false; angular.forEach(deferredQueue, function(deferred) { deferred.reject('用户取消登录'); }); deferredQueue = []; }); } return deferred.promise; } // 非401错误直接返回原错误 return $q.reject(response); } }; }]);
步骤2:注册拦截器到$httpProvider
在应用的配置阶段,把上面的拦截器注册到$http的拦截器列表中:
angular.module('yourApp').config(['$httpProvider', function($httpProvider) { $httpProvider.interceptors.push('authInterceptor'); }]);
步骤3:实现登录模态框控制器
这个控制器负责处理用户的登录请求,验证成功后通知拦截器继续处理原请求:
angular.module('yourApp').controller('LoginModalCtrl', ['$scope', '$modalInstance', '$http', function($scope, $modalInstance, $http) { $scope.loginForm = { username: '', password: '' }; $scope.loginError = ''; $scope.submitLogin = function() { $http.post('/api/Auth/Login', $scope.loginForm) .success(function(response) { // 保存登录后的认证凭证(比如token到localStorage) localStorage.setItem('authToken', response.token); // 关闭模态框,通知拦截器登录成功 $modalInstance.close(); }) .error(function(error) { $scope.loginError = error.message || '登录失败,请检查账号密码'; }); }; $scope.cancel = function() { $modalInstance.dismiss('cancel'); }; }]);
步骤4:登录模态框HTML模板(login-modal.html)
根据你的UI风格调整,这里提供一个基础版本:
<div class="modal-header"> <h3 class="modal-title">会话已过期</h3> </div> <div class="modal-body"> <div class="alert alert-danger" ng-if="loginError">{{loginError}}</div> <form ng-submit="submitLogin()" class="form"> <div class="form-group"> <label>用户名</label> <input type="text" class="form-control" ng-model="loginForm.username" required> </div> <div class="form-group"> <label>密码</label> <input type="password" class="form-control" ng-model="loginForm.password" required> </div> <div class="text-right"> <button type="submit" class="btn btn-primary" ng-disabled="!loginForm.username || !loginForm.password">登录</button> <button type="button" class="btn btn-default" ng-click="cancel()">取消</button> </div> </form> </div>
关键细节说明
- 请求队列与重试:遇到401时,所有等待的请求会被加入队列,登录成功后逐个重试,确保用户的操作不会丢失(比如你原来的
$http.get("/api/Document/GetDocumentsManage")请求,登录后会自动重新执行,success回调也会正常赋值$scope.Documents)。 - 避免无限重试:给重试请求添加
__isRetryRequest标记,如果重试后还是401,就不会再次触发登录流程,直接返回错误。 - 无跳转体验:用模态框代替页面跳转,用户在当前页面就能完成重登,完全保留原有工作状态。
额外优化建议
- 可以添加请求拦截器,自动在请求头里携带认证token:
request: function(config) { var token = localStorage.getItem('authToken'); if (token) { config.headers.Authorization = 'Bearer ' + token; } return config; } - 根据你的业务需求,调整拦截器对状态码的判断(比如有些场景会用403表示权限不足)。
内容的提问来源于stack exchange,提问作者scarson
相关产品推荐
相关产品推荐

