Подтвердить что ты не робот

Ресурс AngularJS: как отключить кодировку сущности url

В моем текущем проекте у меня есть брэнд drupal, который предоставляет службы отдыха для моего интерфейса. Некоторые обращения к моему бэкэнду не очень нравятся объектам url для кодирования.

Итак, мой вопрос: как отключить кодировку URL некоторых параметров?

Пример:

Мне нужно вызвать мой бэкэнд со знаком "+" между разными поисковыми терминами. Например:

http://backend.com/someservice/search/?terms=search+terms+here

Но angular, настройтесь так:

var resource = $resource(
  backendUrl + '/views/:view', {},
    {
      'search': {params:{view:'searchposts'}, isArray:true}
    }
 );

// search posts for the given terms
this.searchPosts = function(terms, limit) {
  resource.search({search:terms.join('+'), limit:limit});
};

Вызывает следующий URL:

http://backend.com/someservice/search/?terms=search%2Bterms%2Bhere

Любые предложения? Спасибо!

4b9b3361

Ответ 1

Обновление: с помощью нового httpParamSerializer в Angular 1.4 вы можете сделать это, написав свой собственный paramSerializer и установив $httpProvider.defaults.paramSerializer.

Ниже применимо только к AngularJS 1.3 (и старше).

Это невозможно без изменения источника AngularJS.

Это делается с помощью $http:

https://github.com/angular/angular.js/tree/v1.3.0-rc.5/src/ng/http.js#L1057

function buildUrl(url, params) {
      if (!params) return url;
      var parts = [];
      forEachSorted(params, function(value, key) {
        if (value === null || isUndefined(value)) return;
        if (!isArray(value)) value = [value];

        forEach(value, function(v) {
          if (isObject(v)) {
            v = toJson(v);
          }
          parts.push(encodeUriQuery(key) + '=' +
                     encodeUriQuery(v));
        });
      });
      if(parts.length > 0) {
        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
      }
      return url;
}

encodeUriQuery использует стандартный encodeUriComponent (MDN), который заменяет "+" на "% 2B"

Слишком плохо, вы не можете перезаписать encodeUriQuery, потому что это локальная переменная внутри функции Angular.

Таким образом, единственная опция, которую я вижу, - это перезаписать window.encodeURIComponent. Я сделал это в перехватчике $http, чтобы минимизировать влияние. Обратите внимание, что исходная функция возвращается только тогда, когда ответ возвращается, поэтому это изменение является глобальным (!), Пока ваш запрос продолжается. Поэтому не забудьте проверить, не нарушает ли это что-то еще в вашем приложении.

app.config(function($httpProvider) {
  $httpProvider.interceptors.push(function($q) {
    var realEncodeURIComponent = window.encodeURIComponent;
    return {
      'request': function(config) {
         window.encodeURIComponent = function(input) {
           return realEncodeURIComponent(input).split("%2B").join("+"); 
         }; 
         return config || $q.when(config);
      },
      'response': function(config) {
         window.encodeURIComponent = realEncodeURIComponent;
         return config || $q.when(config);
      }
    };
  });
});

Ответ 2

AngularJS запускает только метод encodeUriQuery, если вы передаете свои параметры как дополнительный объект. Если вы вручную создадите свою собственную строку параметров и соедините ее с вашим URL-адресом, то Angular не изменит ее.

Очень просто преобразовать объект param самостоятельно, вот пример: Как сериализовать объект в список параметров?

Ответ 3

Обычно вы не хотите этого делать (поскольку на стороне сервера вы можете декодировать URI запроса с помощью функции декодирования URL-адресов, чтобы вернуть свои плюсовые знаки), иногда мы хотим "нарушить" правила.

Сейчас я не могу проверить его (было бы полезно, если бы вы могли создать jsfiddle с тестовым примером для нас, чтобы играть), но, вероятно, вам стоит взглянуть на transformRequest объекта ресурса.

Из документов:

transformRequest - {функция (данные, headersGetter) | Массив.} - преобразование функции или массива таких функций. Функция преобразования принимает тело запроса HTTP и заголовки и возвращает его преобразованное (обычно сериализованной) версии.

Ответ 4

Похоже, что код $resource обертывает эту функциональность в Route.prototype.setUrlParams:

  params = params || {};
  forEach(self.urlParams, function (_, urlParam) {
    val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
    if (angular.isDefined(val) && val !== null) {
      encodedVal = encodeUriSegment(val);
      url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function (match, p1) {
        return encodedVal + p1;
      });
    } else {
      url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function (match,
          leadingSlashes, tail) {
        if (tail.charAt(0) == '/') {
          return tail;
        } else {
          return leadingSlashes + tail;
        }
      });
    }
  });

Source

И похоже, что функция resourceFactory создает замыкание по построенному маршруту, поэтому у вас нет доступа к изменению этого.

Вам конкретно нужно, чтобы это был объект ресурса? Если нет, вы можете создать простой вызов $http и использовать преобразование запроса, как упоминал Антонио.