2014-08-27 137 views
4

我使用angular-http-auth来显示一个登录对话框,每当从服务器返回401“未经授权”的响应。

由于我很酷,我也尝试反序列化我的服务中的响应对象。例如,如果服务请求car,并且响应是{make: Honda, model: Civic},我尝试使用transformResponse将其反序列化为Car对象。

例如:

getCar: function() { 
    return $http.get('/api/car', { 
     method: 'GET', 
     transformResponse: function(data, headers) { 
      var c = angular.fromJson(data); 
      return new Car(c); 
     } 
    }); 
} 

这不会angular-http-auth工作。如果响应是401未经授权,您将得到一个javascript错误。这是因为角度会尝试运行即使响应是401

事实证明,$http拦截器(这是什么angular-http-auth用途)是在transformResponse代码之后运行transformResponse代码。这是一个巨大的问题,因为transformResponse中没有任何代码将工作,如果服务器的响应是401(不会有任何data

这是其他人的问题?你是如何解决它的?如果我使用$http拦截器,我不使用transformResponse吗?

回答

3

迟到了,我知道,但任何人来到这里,从谷歌和我一样(我也贴这是在related issue与角回购提交评论):

我还发现这是令人困惑的是响应拦截器在transformResponse方法后运行。我添加了一个方法到$http.defaults.transformResponseHere是关于如何做到这一点的文档中的一个例子。

所以,如果你需要基本上有一个运行响应拦截之前transformResponse方法,这应该这样做:

'use strict'; 

angular.module('app') 
    .run(function ($http) { 
    $http.defaults.transformResponse.push(function (data, headers) { 
     // do stuff here before the response transformation 

     // Be sure to return `data` so that the next function in the queue can use it. 
     // Your services won't load otherwise! 
     return data; 
    }); 
    }); 

如果你的服务或HTTP调用没有自己的响应变压器,你现在很好。

如果你的服务有自己的transformResponse方法,它们实际上会覆盖所有的默认转换器(在长时间阅读文档后我发现了这个),并且上面的代码不会运行。

为了规避这种情况,您可以在文档中关注this example

1

为了解决这个问题,我不再使用transformResponse。如果它在$ http拦截器之前运行,我只能看到transformResponse的点。

为了使用angular-http-auth并在您的服务中反序列化响应,您可以编写服务以便它们先执行HTTP请求,然后在回调函数中反序列化响应。

作为一个例子,这里是我怎么会在OP已经重构的例子:

Plunker

services.factory('HttpCarService', function($resource, $q) { 
    var resource = $resource('/api/car'); 

    return { 

    getCar: function() { 

     var deferred = $q.defer(); 
     var car = null; 

     var successCallback = function(data, status, headers, config) { 
     var c = angular.fromJson(data); 
     car = new Car(c); 
     deferred.resolve(car); 
     }; 

     var errorCallback = function(data, status, headers, config) { 
     deferred.reject("something wrong"); 
     }; 

     var result = resource.get(successCallback, errorCallback); 
     return deferred.promise; 
    } 
    }; 

}); 

这种模式也将工作,如果data是一个数组。

$http拦截器将在执行任一回调方法之前运行。如果你的$ resource需要url参数,你可以让getCar()函数接受一个配置对象作为参数,并且在你进行$ resource.get()调用时传递必要的信息。