javascriptangularjsuriencoding

Angularjs How uri components are encoded


I was expecting AngularJS to encode query string parameters using the standard javascript function encodeURIComponent. According to the following test it is not the case:

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();
 }));
});

The test fails with the following error:

$http encodes uri components correctly
Error: Unexpected request: GET /api/process?data=Hello+from+http:%2F%2Fexample.com
Expected GET /api/process?data=Hello%20from%20http%3A%2F%2Fexample.com

To sum up:

What uri component (aka query string parameters) encoding method should I expect with AngularJS?


Solution

  • Angular (at least 1.3) doesn't only use encodeURIComponent and changes some replacements (like " " to "+").

    this is the commit explaining why : https://github.com/angular/angular.js/commit/9e30baad3feafc82fb2f2011fd3f21909f4ba29e

    And here's what you can see in 1.3 sources :

    /**
     * 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' : '+'));
    }
    

    note that pctEncodeSpaces is hardcoded to true;

    Here's what you can do to decode URI parameters

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