使用 AngularJS 的全局 Ajax 错误处理程序

Posted

技术标签:

【中文标题】使用 AngularJS 的全局 Ajax 错误处理程序【英文标题】:Global Ajax error handler with AngularJS 【发布时间】:2012-08-11 20:39:54 【问题描述】:

当我的网站是 100% jQuery 时,我曾经这样做:

$.ajaxSetup(
    global: true,
    error: function(xhr, status, err) 
        if (xhr.status == 401) 
           window.location = "./index.html";
        
    
);

为 401 错误设置全局处理程序。现在,我使用带有$resource$http 的angularjs 向服务器发出我的(REST)请求。有没有办法用 Angular 类似地设置全局错误处理程序?

【问题讨论】:

它是否可能与AngularJS Failed Resource GET 重复? 不,我们要为应用程序做一个全局错误 401 处理程序 大声笑,您是否考虑过您想要的但具有不同的 http 状态(您可以更改)?无论如何,pkozlowski.opensource 的回答告诉你如何去做 不,这更像是 Justen 的答案...这与您所说的问题不重复 【参考方案1】:

我还在用 Angular 构建一个网站,但在处理全球 401 时遇到了同样的障碍。当我看到这篇博文时,我最终使用了 http 拦截器。也许你会发现它和我一样有用。

"Authentication in AngularJS (or similar) based application.",espeo 软件

编辑:最终解决方案

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives'], function ($routeProvider, $locationProvider, $httpProvider) 

    var interceptor = ['$rootScope', '$q', function (scope, $q) 

        function success(response) 
            return response;
        

        function error(response) 
            var status = response.status;

            if (status == 401) 
                window.location = "./index.html";
                return;
            
            // otherwise
            return $q.reject(response);

        

        return function (promise) 
            return promise.then(success, error);
        

    ];
    $httpProvider.responseInterceptors.push(interceptor);

【讨论】:

需要返回$q.reject(response);当状态 == 401 时,避免嘈杂的角度误差 @daniellmb。这取决于。如果您真的想转到另一个页面,而不仅仅是更改视图,那么您实际上应该使用 $window。如果您的登录页面只是另一个带有角度的视图和控制器,那么您可以使用 $location.path @uriDium 没错,我的意思是使用 Angular 提供的对象,以便您可以模拟和测试。 $httpProvider.responseInterceptors 现在已弃用。见docs.angularjs.org/api/ng.$http#description_interceptors。 成功时你需要像return response || $q.when(response);一样返回,这样如果响应为空,那么也会返回一个promise对象。【参考方案2】:

请注意,Angular 1.1.4 已弃用 responseInterceptors。 您可以在下面找到基于official docs 的摘录,展示了实现拦截器的新方法。

$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) 
  return 
    'response': function(response) 
      // do something on success
      return response || $q.when(response);
    ,

   'responseError': function(rejection) 
      // do something on error
      if (canRecover(rejection)) 
        return responseOrNewPromise;
      
      return $q.reject(rejection);
    
  ;
);

$httpProvider.interceptors.push('myHttpInterceptor');

这是它在我使用 Coffeescript 的项目中的样子:

angular.module("globalErrors", ['appStateModule']).factory "myHttpInterceptor", ($q, $log, growl) ->
  response: (response) ->
    $log.debug "success with status #response.status"
    response || $q.when response

  responseError: (rejection) ->
    $log.debug "error with status #rejection.status and data: #rejection.data['message']"
    switch rejection.status
      when 403
        growl.addErrorMessage "You don't have the right to do this"
      when 0
        growl.addErrorMessage "No connection, internet is down?"
      else
        growl.addErrorMessage "#rejection.data['message']"

    # do something on error
    $q.reject rejection

.config ($provide, $httpProvider) ->
  $httpProvider.interceptors.push('myHttpInterceptor')

【讨论】:

但是在 responseError 拦截器中你将没有 xhr 数据或其他有用的信息。甚至无法判断它是否可恢复。 @zw0rk 你会......在responseErrorrejection 里面有你需要的一切。 最后一行 $httpProvider... 是否被包裹在 config() 块中? 确实,我已经编辑了我的答案,以展示我是如何使用 Coffeescript 在我的项目中做到这一点的。如果您喜欢在 javascript 中使用 js2coffee.org,请使用它。 不应该在responseError 函数下对response 的所有引用实际上都是对rejection 的引用(或者参数应该将其名称更改为response【参考方案3】:

使用此内容创建文件<script type="text/javascript" src="../js/config/httpInterceptor.js" ></script>

(function()
  var httpInterceptor = function ($provide, $httpProvider) 
    $provide.factory('httpInterceptor', function ($q) 
      return 
        response: function (response) 
          return response || $q.when(response);
        ,
        responseError: function (rejection) 
          if(rejection.status === 401) 
            // you are not autorized
          
          return $q.reject(rejection);
        
      ;
    );
    $httpProvider.interceptors.push('httpInterceptor');
  ;
  angular.module("myModule").config(httpInterceptor);
());

【讨论】:

@ThilakRaj 上面的代码应该在每个 http 请求上运行。因此,在 Chrome 中创建两个断点,一个在“return response”行,一个在“return $q.reject”,以检查它是否正常运行。

以上是关于使用 AngularJS 的全局 Ajax 错误处理程序的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS和Spring MVC的Ajax GET错误

获取从 angularJS 中的异步 $http 服务获得的对象,以便在 $scope 中全局访问

AngularJS ajax调用中的CORS错误[重复]

在角度,angularjs和jQuery技术构建的应用程序中,处理客户端全局错误的最佳和最佳方法是什么?

使用AngularJS返回xml的跨域ajax请求

用于附加全局焦点事件的 AngularJS 方式