Reputation: 856
We need an encoded semi-colon character in our url parameter but angular does not encode this character.
The resource we use looks something like this:
app.factory('TestResource', ['$resource', function ($resource) {
return $resource('http://somedomain.com');
}]);
app.run(['TestResource', function (TestResource) {
TestResource.query({
q: 'sin;sout'
});
}]);
This is the result we get:
http://somedomain.com/?q=sin;sout
We want the url to be:
http://somedomain.com/?q=sin%3Bsout
But if we pre-encode the parameter before sending the % char get's encoded like this:
http://somedomain.com/?q=sin%253Bsout
How can we get the desired result? (http://somedomain.com/?q=sin%3Bsout)
Upvotes: 4
Views: 4367
Reputation: 6145
There is a closed issue for this https://github.com/angular/angular.js/issues/9224
path: Don't escape semicolons. Breaks matrix parameters, and no evidence that Angular's current behavior is problematic.
query: Escaping the entire query string would be unwise, as it breaks an established (albeit archaic) expectation for servers to be able to handle semicolon-delimited query strings.
query values: Probably safe to escape, especially if the server interprets semicolons as query delimiters. Passing complex data types (ie. JSON) via query parameters is a bad idea, but "real-world" string values often contain semicolons, and it seems like a good idea to escape them.
I'll go with zeroflagL's answer but only changing the query values. Like this:
$provide.decorator('$httpBackend', function($delegate) {
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
var a = document.createElement('a');
a.href = url;
if(a.search.length > 1) {
var params = a.search.substring(1).split('&');
for (var i=0; i<params.length; i++) {
var param = params[i].split('=');
if(param[1]) {
params[i] = [param[0], param[1].replace(';', '%3B')].join('=');
}
}
url = url.substring(0, url.lastIndexOf('?')) + '?' + params.join('&');
}
$delegate(method, url, post, callback, headers, timeout, withCredentials, responseType);
};
});
Upvotes: 1
Reputation: 31
Building on zeroflagL's answer one could consider changing the replace to change all occurrences of the semi-colon (as it is written it will only replace the first semi-colon):
url = url.replace(/;/g, '%3B');
Upvotes: 3
Reputation: 26828
Angular uses its own function to encode the URL. And that function doesn't encode characters that usually don't need to be encoded like /
or ?
. ;
is such a character, too. It's used in matrix URIs, e.g. So Angular's behavior actually conforms to the standard, but it could be a problem when such characters are used literally, i.e. without a special meaning. That seems to be the case here.
Since the URL is build just before sending the request, there's not much we can do. There is kind of a loophole though: Only parameters are encoded, not the base URL. So any workaround would involve creating the URL or at least a part of it yourself.
You could add an interceptor, that adds the properly encoded parameters to the URL before Angular does it. You could even completely replace Angular's behavior that way.
UPDATE:
Another solution came to my mind. The $http
service delegates sending the actual request to the $httpBackend
service which receives the already constructed URL. Using a decorator you can replace either the ;
or the incorrectly encoded %253B
with %3B
right before the request is sent:
app.config(function($provide) {
$provide.decorator('$httpBackend', function($delegate) {
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
url = url.replace(';', '%3B');
$delegate(method, url, post, callback, headers, timeout, withCredentials, responseType);
};
})
});
Upvotes: 6
Reputation: 74738
You can use encodeURIComponent()
method:
q: encodeURIComponent('sin;sout')
Upvotes: 0