AngularJS 中的 401 未经授权的错误处理

Posted

技术标签:

【中文标题】AngularJS 中的 401 未经授权的错误处理【英文标题】:401 unauthorized error handling in AngularJS 【发布时间】:2013-09-11 03:24:42 【问题描述】:

我是 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,会发生什么? 您使用的是什么版本的 Angular?这很重要,因为 responseInterceptors 在 1.2 中发生了变化 @TheSharpieOne 我的版本是 v1.0.6。是这个原因吗? @akonsu 它会捕获除 200 或 300 之外的任何 ajax 错误。我很痛苦的是为什么它无法捕获 401 状态代码。 找到了AngularJs没有捕获401状态的原因,它不应该在调用JSONP请求时捕获401。只要将方法更改为“GET”,它就会很好地捕捉到。 【参考方案1】:

接受的答案不适用于更高版本的 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

【讨论】:

【参考方案2】:

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

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) 时如何向用户显示他退出的原因?【参考方案4】:

遵循类似的解决方案...

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");

以上是关于AngularJS 中的 401 未经授权的错误处理的主要内容,如果未能解决你的问题,请参考以下文章

从角度访问webapi时出现401未经授权的错误

如果刷新(JWT)令牌未经授权(401响应),AngularJS重定向到登录

在 grails 应用程序中调用 spring security rest 插件登录时出现 401 未经授权的错误

Spring Boot / Spring Security中的错误401未经授权

ReactJS MeteorJS Axios // 401 [未经授权] 错误

尝试使用帐户服务从 Gmail 帐户读取 Gsuite 中的公司电子邮件时出现 401 未经授权的错误