Angularjs Как кодируются компоненты URI

Я ожидал, что AngularJS закодирует параметры строки запроса, используя стандартную функцию javascript encodeURIComponent, Согласно следующему тесту это не так:

describe('$http', function () {
 it('encodes uri components correctly', inject(function($http, $httpBackend) {
   var data = 'Hello from http://example.com';
   $httpBackend.expectGET('/api/process?data=' + encodeURIComponent(data));
   $http({ method: 'GET', url: '/api/process', params: { data: data } });
   $httpBackend.flush();
 }));
});

Тест не пройден со следующей ошибкой:

$ http правильно кодирует компоненты URI
Ошибка: неожиданный запрос: GET /api/process?data=Hello+from+http:%2F%2Fexample.com
Ожидаемый GET /api/process?data=Hello%20from%20http%3A%2F%2Fexample.com

Подводить итоги:

  • Ожидаемая кодировка: Hello%20from%20http%3A%2F%2Fexample.com
  • Фактическая кодировка: Hello+from+http:%2F%2Fexample.com

Какой метод кодирования компонента uri (он же параметры строки запроса) мне следует ожидать с AngularJS?

3 ответа

Решение

Angular (не менее 1,3) не только использует encodeURIComponent и меняет некоторые замены (например, " " на "+").

это коммит, объясняющий почему: https://github.com/angular/angular.js/commit/9e30baad3feafc82fb2f2011fd3f21909f4ba29e

И вот что вы можете увидеть в 1.3 источниках:

/**
 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
 * encoded per http://tools.ietf.org/html/rfc3986:
 *    query       = *( pchar / "/" / "?" )
 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 *    pct-encoded   = "%" HEXDIG HEXDIG
 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
 *                     / "*" / "+" / "," / ";" / "="
 */
function encodeUriQuery(val, pctEncodeSpaces) {
  return encodeURIComponent(val).
             replace(/%40/gi, '@').
             replace(/%3A/gi, ':').
             replace(/%24/g, '$').
             replace(/%2C/gi, ',').
             replace(/%3B/gi, ';').
             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}

Обратите внимание, что pctEncodeSpaces жестко true;

Вот что вы можете сделать, чтобы декодировать параметры URI

decodeURIComponent(val.
             replace('@', '%40').
             replace(':', '%3A').
             replace('$', '%24').
             replace(',', '%2C').
             replace(';', '%3B').
             replace('+', '%20'));

По моему скромному мнению, AngularJS неправильно кодирует так же, как сегменты пути URI и параметры запроса URI. Для меня это ошибка, и я действительно выдвинул запрос на исправление.

Тест, который я ввел в запросе на удаление, фактически подтверждает эту ошибку (проверял ее с обоими AngularJS 1.3.* и текущий master).

Похоже, что когда вы передаете параметры предварительного кодирования. Вы кодируете URL, но после передачи некодированного URL через параметр данных JSON. Может быть, это изменение вашего кода будет работать.

describe('$http', function () {
 it('encodes uri components correctly', inject(function($http, $httpBackend) {
   var data =  encodeURIComponent('Hello from http://example.com');
   $httpBackend.expectGET('/api/process?data=' + encodeURIComponent(data));
   $http({ method: 'GET', url: '/api/process', params: { data: data } });
   $httpBackend.flush();
 }));
});

Кроме того, после того, как вы взяли только фрагмент кодировки URL и поместили его в скрипку: http://jsfiddle.net/eNtgL/1/

Кажется, что он работает правильно, вы можете исследовать внешние факторы, вызывающие проблему с вашим URL. Есть также несколько других опций, описанных здесь в этом

Кодировать URL в JavaScript?

Другие вопросы по тегам