Динамические заголовки ресурсов

Я хотел бы иметь сервис, предоставляющий ресурс, как в следующем коде:

   angular.module('myApp.userService', ['ngResource'])
  .factory('UserService', function ($resource)
  {
    var user = $resource('/api/user', {},
          {
            connect: { method: 'POST', params: {}, isArray:false }
          });
    return user;
  }

Затем при использовании действия connect я хотел бы динамически передать HTTP-заголовок, что означает, что он может измениться для каждого вызова. Вот пример, в контроллере, пожалуйста, см. Комментарий в коде:

 $scope.user = UserService;

 $scope.connect = function ( user )
        {
          var hash = 'Basic ' + Base64Service.encode(user.login + ':' + user.password);

          // I would like this header to be computed 
          // and used by the user resource
          //  each time I call this function
          $scope.user.headers = [{Authorization: hash}];

          $scope.user.connect( {},
              function()
              {
                  // successful login
                  $location.path('/connected');
              }
              ,function()
              {
                  console.log('There was an error, please try again');
              });
       }

Знаете ли вы способ сделать это, либо напрямую, либо с помощью трюка?


Заключительные мысли

Принятый ответ не полностью отвечает на вопрос, поскольку заголовки не являются полностью динамическими, поскольку factory возвращает фактически factory (!), что не соответствует моему коду.

Поскольку $resource является factory, нет возможности сделать его динамическим.

Я, наконец, уничтожаю объект ресурса каждый раз, когда пользователь подключается. Таким образом, у меня есть ресурс с заголовком, вычисленным, когда пользователь подключается.

Решение, предоставленное @Stewie, полезно для этого, поэтому я сохраняю его как принятое.


Вот как я сделал соединение, которое можно использовать несколько раз, когда ресурс уничтожается/воссоздается, когда (повторное) соединение:

 this.connect = function (user)
 {
    self.hash = 'Basic ' + Base64Service.encode(user.login + ':' + user.password);
console.log("CONNECT login:" + user.login + " - pwd:" + user.password + " - hash:" + self.hash);

if (self.userResource)
{
  delete self.userResource;
}

self.userResource = $resource('/api/user/login', {}, {
  connect: {
    method: 'POST',
    params: {},
    isArray: false,
    headers: { Authorization: self.hash }
  }
});

var deferred = $q.defer();
self.userResource.connect(user,
  function (data)
  {
    //console.log('--------- user logged in ----- ' + JSON.stringify(data));
    // successful login
    if (!!self.user)
    {
      angular.copy(data, self.user);
    }
    else
    {
      self.user = data;
    }

    self.setConnected();

    storage.set('user', self);

    deferred.resolve(self);
  },
  function (error)
  {
    self.user = {};
    self.isLogged = false;

    storage.set('user', self);

    deferred.reject(error);
  }
);

return deferred.promise;

};

Ответ 1

Начиная с angularjs v1.1.1 и ngResource v.1.1.1, это можно выполнить, используя свойство headers объекта действия $resource.

Вы можете обернуть свой ресурс в функцию, которая принимает пользовательские заголовки в качестве параметра и возвращает объект $resource с вашими настраиваемыми заголовками, установленными в соответствующих определениях действий:

PLUNKER

var app = angular.module('plunker', ['ngResource']);

app.controller('AppController',
  [
    '$scope',
    'UserService',
    function($scope, UserService) {
      $scope.user = {login: '[email protected]', password: '123'};

      $scope.connect = function() {
        // dropping out base64 encoding here, for simplicity
        var hash = 'Basic ' + $scope.user.login + ':' + $scope.user.password;
        $scope.user.headers = [{Authorization: hash}];

        UserService({Authorization: hash}).connect(
          function () {
            $location.url('/connected');
          },
          function () {
            console.log('There was an error, please try again');
          }
        );

      };

    }
  ]
);

app.factory('UserService', function ($resource) {
  return function(customHeaders){
    return $resource('/api/user', {}, {
      connect: { 
        method: 'POST',
        params: {},
        isArray: false,
        headers: customHeaders || {}
      }
    });
  };

});

Ответ 2

Я установил свои услуги немного по-другому.

angular.module('MyApp').factory('UserService',function($resource, localStorageService) {

    var userResource = function(headers) {
        return $resource("api/user", {},
            {
                get: {
                    method: 'GET',
                    headers: headers
                },

                create: {
                    method: 'POST',
                    headers: headers
                }
            }
        );
    };

    return {

        api: userResource,

        get: function(userid){
            var service = this;
            return service.api({"token": "SomeToken"}).get({userid: userid}, function (data){
                return data;
            });
        },

        create: function(user){
            var service = this;
            return service.api({"token": localStorageService.get("token")}).create({user: user}, function (data){
                return data;
            });
        }

    };

});