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

请求错误时重试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:41:36