AngularJS中处理401未授权错误

17

我对AngularJS非常陌生,现在已经花费3天时间找到一种处理401状态的方法。我尝试使用拦截器、$http、$resource等方式...但没有任何效果。我的应用在同一服务器上调用JSONP调用。当错误发生时,它被捕获在错误回调函数中。但是状态永远是0,响应是未定义的。

首先,我尝试了这个拦截器

app.config(['$httpProvider', function($httpProvider) {
$httpProvider.responseInterceptors.push(['$q', function($q) {
    return function(promise) {
        return promise.then(function(response) {
            console.log('success in interceptor');
            return response; 
        }, function(response) {
            console.log('error in interceptor');
            console.log(response);
            if (response.status === 401) {
                response.data = { 
                    status: false, 
                    description: 'Authentication required!'
                };
                return response;
            }
            return $q.reject(response);
        });
    }
}]);
}]);

其次,在控制器中使用 $resource 也进行了尝试。

  $scope.fetchData = function(fromDate, toDate){
        Cancel.get({from: fromDate, to: toDate, perPage: 99999},
                    function(data){                            
                      $scope.cancels  = $scope.filteredCancels = data.data;
                      $scope.search();
                    },
                    function(response) {
                      $scope.errorMessage = '<h4>Error : '+response.status+'</h4>';
                      window.location = "/";
                    });              
      }; 

第三,尝试使用 $http 而不是 $resource

  $scope.fetchData = function(fromDate, toDate){
     $http.jsonp('http://host:8900/api/cancellations?callback=JSON_CALLBACK')
         .success(function(data, status, headers, config) {
             console.log(status);
          })
         .error(function(data, status, headers, config) {
             console.log(status);              
          }; 

这是用于JSONP调用的头信息

Request URL:http://host:8900/api/cancellations?callback=angular.callbacks._0
Request Method:GET
Status Code:401 Unauthorized
Request Headersview source
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__utma=149207145.339724205.1374885003.1377550245.1378313049.3; __utmc=149207145; __utmz=149207145.1378313049.3.2.utmcsr=cyphersmart.qc3deva.electricmail.com:8900|utmccn=(referral)|utmcmd=referral|utmcct=/; remember_username=elie.kim%40electricmail.com; PHPSESSID=gdoemlp5jltqq62etc5gfuh653; cookie=cookiecheck; __utma=1.789184132.1378340585.1378499390.1378504453.10; __utmb=1.3.10.1378504453; __utmc=1; __utmz=1.1378340585.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:host:8900
Referer:http://host:8900/reports/cancels/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
Query String Parametersview sourceview URL encoded
callback:angular.callbacks._0
Response Headersview source
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection:keep-alive
Content-Type:application/json; charset=utf-8
Date:Fri, 06 Sep 2013 22:02:13 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive:timeout=20
Pragma:no-cache
Server:nginx/0.7.65
Transfer-Encoding:chunked

我找不到处理未经授权的状态码401的方法,我已经尝试了所有的方法。如果你能给我一些提示或者建议,我将非常感激。


如果您在浏览器中导航到您的URL,会发生什么? - akonsu
你使用的 Angular 版本是什么?这很重要,因为 responseInterceptors 在 1.2 版本中发生了变化。 - TheSharpieOne
@akonsu 它可以捕获除200或300之外的任何ajax错误。我所遭受的困扰是为什么它无法捕获401状态码。 - Elie Kim
找到了AngularJs无法捕获401状态的原因,它在调用JSONP请求时不应该捕获401。一旦将方法更改为“GET”,它就可以很好地捕获了。 - Elie Kim
我的Backbone和JQuery的经验在捕获401状态方面没有任何问题;这意味着$.ajaxSetup可以捕获401,但AngularJs无法做到。对吗? - Elie Kim
显示剩余2条评论
4个回答

9

接受的答案在后续版本的Angular中不起作用。使用1.5.x(甚至更早)需要以不同的方式编写拦截器:

// http interceptor to handle redirection to login on 401 response from API
app.factory('httpResponseInterceptor', ['$q', '$rootScope', '$location', function($q, $rootScope, $location) {
    return {
        responseError: function(rejection) {
            if (rejection.status === 401) {
                // Something like below:
                $location.path('signin/invalidSession');
            }
            return $q.reject(rejection);
        }
    };
}]);

使用以下方式申请:

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('httpResponseInterceptor');
});

请查看此处以获取更多信息 https://docs.angularjs.org/api/ng/service/$http#interceptors


4
我最近需要做类似的事情,以下是我的拦截器:

我最近需要做很相似的事情,这是我的拦截器

app.factory("HttpErrorInterceptorModule", ["$q", "$rootScope", "$location",
    function($q, $rootScope, $location) {
        var success = function(response) {
            // pass through
            return response;
        },
            error = function(response) {
                if(response.status === 401) {
                    // dostuff
                }

                return $q.reject(response);
            };

        return function(httpPromise) {
            return httpPromise.then(success, error);
        };
    }
]).config(["$httpProvider",
    function($httpProvider) {
        $httpProvider.responseInterceptors.push("HttpErrorInterceptorModule");
    }
]);

根据您的使用情况进行了微调


3

如果任何API调用返回401,我们必须将用户重定向到登录页面。对于这项工作,Angular的HTTP拦截器非常出色。正如您从上面的app.js中看到的那样,它已经被推送到管道中:

httpProvider.responseInterceptors.push('httpInterceptor');

拦截器实现本身,
'use strict';

angular.module('dashboardApp').factory('httpInterceptor', function httpInterceptor ($q, $window, $location) {
  return function (promise) {
      var success = function (response) {
          return response;
      };

      var error = function (response) {
          if (response.status === 401) {
              $location.url('/login');
          }

          return $q.reject(response);
      };

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

当重定向到location.path(/login)时,如何告诉用户他为什么被注销? - maumercado

2

以下是类似的解决方案...

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

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

        function success(response) {
            return response;
        }

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

            if (status == 401) {
                $location.url('/login');
                return;
            }

            return $q.reject(response);

        }

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

    }];
    $httpProvider.responseInterceptors.push(httpInterceptor);
});

$httpProvider.interceptors.push("HttpErrorInterceptorModule"); - Krack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接