Angular不对url中的分号字符进行编码

时间:2014-11-07 09:24:09

标签: angularjs

我们需要在url参数中使用编码的分号字符,但angular不会对此字符进行编码。

我们使用的资源看起来像这样:

app.factory('TestResource', ['$resource', function ($resource) {
    return $resource('http://somedomain.com');
}]);

app.run(['TestResource', function (TestResource) {
    TestResource.query({
        q: 'sin;sout'
    });
}]);

这是我们得到的结果:

http://somedomain.com/?q=sin;sout

我们希望网址为:

http://somedomain.com/?q=sin%3Bsout

但是如果我们在发送%char get之前对参数进行预编码,则编码如下:

http://somedomain.com/?q=sin%253Bsout

我们如何才能获得理想的结果? (http://somedomain.com/?q=sin%3Bsout

4 个答案:

答案 0 :(得分:5)

Angular使用自己的函数对URL进行编码。并且该函数不会编码通常不需要像/?那样编码的字符。 ;也是这样一个角色。它用于矩阵URI,例如因此,Angular的行为实际上符合标准,但当字面上使用这些字符时,可能会成为问题,即没有特殊含义。这似乎就是这种情况。

由于URL是在发送请求之前构建的,因此我们无能为力。但是有一个漏洞:只编码参数,而不是基本URL。因此,任何解决方法都需要自己创建URL或至少部分URL。

您可以添加一个拦截器,在Angular执行之前将正确编码的参数添加到URL。你甚至可以用这种方式完全取代Angular的行为。

<强>更新

我想到了另一个解决方案。 $http服务委托将实际请求发送到接收已构造的URL的$httpBackend服务。使用装饰器,您可以在发送请求之前将;或编码错误的%253B替换为%3B

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

答案 1 :(得分:2)

在zeroflagL的答案基础上,可以考虑更改替换以更改所有出现的分号(因为它写的只会替换第一个分号):

url = url.replace(/;/g, '%3B');

答案 2 :(得分:0)

您可以使用encodeURIComponent()方法:

q: encodeURIComponent('sin;sout')

答案 3 :(得分:0)

https://github.com/angular/angular.js/issues/9224

存在已解决的问题
  

路径:不要使用分号。打破矩阵参数,并且没有证据表明Angular的当前行为存在问题。

     

查询:转义整个查询字符串是不明智的,因为它打破了服务器能够处理以分号分隔的查询字符串的既定(虽然过时)期望。

     

查询值:可能安全逃脱,尤其是服务器将分号解释为查询分隔符时。通过查询参数传递复杂数据类型(即JSON)是一个坏主意,但&#34;真实世界&#34;字符串值通常包含分号,并且逃避它们似乎是一个好主意。

我会使用zeroflagL的答案,但只会更改查询值。像这样:

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