angular-http-auth与$ http transformResponse

每当从服务器返回401 "unauthorized"响应时,我正在使用angular-http-auth来显示登录对话框 .

由于我很酷,我也尝试在我的服务中反序列化响应对象 . 例如,如果服务请求 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 Unauthorized,那么'll get a javascript error. It' s因为angular会尝试运行该 transformResponse 代码,即使响应是401 .

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

这对其他人来说是个问题吗?你是怎么绕过它的?如果我使用 $http 拦截器,我不会使用 transformResponse 吗?

回答(2)

2 years ago

我知道,在派对上晚了,但对于像我一样从谷歌来到这里的人(我也发布了这篇文章作为对Angular回购提交的related issue的评论):

我还发现,在 transformResponse 方法之后运行响应拦截器令人困惑 . 我为 $http.defaults.transformResponse 添加了一个方法 . Here是有关如何执行此操作的文档中的示例 .

所以,如果你需要基本上有一个在 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 .

2 years ago

为了解决这个问题,我不再使用 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 params,你可以让getCar()函数接受一个config对象作为参数,并在你进行$ resource.get()调用时传递必要的信息 .