Параметрировать базовый URL-адрес в ресурсе Angular JS $

Я использую несколько определений ресурсов Angular JS $, все из которых извлекают свой базовый URL из службы конфигурации. Например:

$resource(config.baseURL() + '/api/v2/foo/:id', {id: '@id'})

$resource(config.baseURL() + '/api/v2/bar/:id', {id: '@id'})

Причина этого заключается в том, что базовый URL-адрес может быть изменен с помощью параметра строки запроса при первом загрузке приложения.

Я понял, что (очевидно, ретроспективно) URL-адрес, используемый ресурсом $, инициализируется только один раз, поэтому можно получить условие гонки, когда URL-адрес для определенного ресурса $инициализируется до того, как будет обработан параметр строки запроса базового URL-адреса с. Поэтому я попытался изменить объявление $resource на это:

$resource(':baseURL/api/v2/foo/:id', {baseURL: config.baseURL(), id: '@id'})

К сожалению, базовый URL-адрес получает экранирование - // преобразуется в %2F%2F - поэтому весь URL-адрес не работает должным образом.

Есть ли способ подавить экранирование для этого параметра? (или, может быть, лучший способ решить проблему в целом)?

Ответ 1

Другой способ справиться с этим - использовать провайдер и настроить его на этапе config.

Вот пример чего-то подобного, который я сделал некоторое время назад.

.provider('Environment', function () {
    var environments = {
        dev: {
            root: 'http://localhost',
            port: 3000,
            api: '/api',
            version: 'v1'
        }
    };
    var selectedEnv = 'dev';
    var self = this;

    this.setEnvironments = function (envs) {
        if (!Object.keys(envs).length)
            throw new Error('At least one environment is required!');

        environments = envs;
    };

    this.setActive = function (env) {
        if (!environments[env])
            throw new Error('No such environment present: ' + env);

        selectedEnv = env;
        return self.getActive();
    };

    this.getEnvironment = function (env) {
        if (!env)
            throw new Error('No such environment present: ' + env);
        return environments[env];
    };

    this.getActive = function () {
        if (!selectedEnv)
            throw new Error('You must configure at least one environment');

        return environments[selectedEnv];
    };

    this.getApiRoute = function () {
        var active = self.getActive();
        return active.root + (active.port ? ':' + active.port : '') +
            active.api + (active.version ? '/' + active.version : '');
    };

    this.$get = [function () {
        return self;
    }];
})

Затем в фазе конфигурации:

.config(function (EnvironmentProvider) {

    EnvironmentProvider.setEnvironments({
        dev: {
            root: 'http://10.0.0.3',
            api: '/api',
            version: 'v1'
        },
        localonly: {
            root: 'http://localhost',
            api: '/api',
            version: 'v1'
        },
        prod: {
            root: 'https://myapp.mybackend.com',
            api: '/api',
            version: 'v1'
        }
    });

    //Set prod as the active schema
    EnvironmentProvider.setActive('prod');
});

Позже в некоторых контроллерах/службах/ factory:

.factory('API',function($resource, Environment){
 return {
  User: $resource(Environment.getApiRoute() + '/users/:id', {id: '@_id'}),
  OtherResource: $resource(Environment.getApiRoute() + '/otherresource/:id', {id: '@_id'})
 }
});

Ответ 2

Почему бы не воспользоваться сервисом $location?

Например, как насчет следующего для обработки базового url, и, если приложение запущено с localhost, укажите номер порта? Кроме того, уметь включать либо http, либо https на основе текущего URL?

var host = $location.host();
if (host === "localhost")
  host += ":" + $location.port();
var url = $location.protocol() + "://" + host + "/whateverElseYouWantInThePath";

а затем используйте url, где он вам нужен?

Ответ 3

Из определения ресурса

  • @param {string} url Шаблон параметризованного URL с параметрами с префиксом :, как в
  • /user/:username. Если вы используете URL-адрес с номером порта (например,
  • http://example.com:8080/api), вам нужно будет избежать символа двоеточия перед портом
  • например: djResource('http://example.com\\:8080/api').

Итак, вы должны определить свой config.baseURL() следующим образом:

config.baseUrl = function(){
   return 'http://server.com\\:port/rest_part/';
}

Ответ 4

Вот ужасное, но работающее решение. Вместо...

$resource(config.baseURL() + '/api/v2/foo/:id', {id: '@id'})

... который оценивается только один раз, использует объект, который реализует String-методы, которые ngResource оценивает перед каждым запросом:

var url = {};
url.value = function() {return config.baseURL() + '/api/v2/foo/:id'};
url.split = function (separator,limit) { return url.value().split(separator,limit) };
url.replace = function (match, other) { return url.value().replace(match, other) };
url.toString = function() { return url.value(); }
$resource(url, {id: '@id'})