Angular不会对URL中的分号字符进行编码。

4
我们需要在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

我们希望URL为:
http://somedomain.com/?q=sin%3Bsout

但是,如果在发送之前对参数进行预编码,则 % 字符会被编码为:

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

我们该如何获得期望的结果?(http://somedomain.com/?q=sin%3Bsout)

这可能听起来像一个愚蠢的问题,但你认为为什么URL没有被正确编码呢?根据您的检查方式,您实际上可能会看到解码后的URL。此外,它是否编码并不重要。在任何操作发生之前,通常会在服务器端对其进行解码。 - a better oliver
我们使用这个来构建InfluxDB的查询。我们可以在浏览器中简单地看到URL,如果我们手动更改URL,它就能工作。作为一种解决方法,我们现在使用jQuery和一个ajax请求,它正确地编码了URL。 - joente
4个回答

6
Angular使用自己的函数对URL进行编码。该函数不会对通常不需要编码的字符进行编码,例如/?。而;也是这样一个字符。它在矩阵URI中使用,例如。因此,Angular的行为实际上符合标准,但当这些字符被字面使用时,即没有特殊含义时,这可能会成为问题。这似乎是这里的情况。
由于URL是在发送请求之前构建的,因此我们无法做太多事情。但有一种漏洞:只有参数被编码,而不是基本URL。因此,任何解决方法都涉及创建URL或至少其一部分。
您可以添加拦截器,在Angular对URL进行编码之前将正确编码的参数添加到URL中。甚至可以完全替换Angular的行为。
更新:
我想到了另一种解决方案。$http服务将实际请求委托给$httpBackend服务,后者接收已构造的URL。使用装饰器,您可以在发送请求之前将;或错误编码的%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);
    };
  })
});

3

在zeroflagL的回答基础上,我们可以考虑将replace替换为更改所有分号的方法(因为它只会替换第一个分号):

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

1

这个问题已经有一个关闭的解决方案了 https://github.com/angular/angular.js/issues/9224

路径: 不要转义分号。这会破坏矩阵参数,并且没有证据表明Angular当前的行为有问题。

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

查询值: 可能是安全的进行转义,特别是如果服务器将分号解释为查询分隔符。通过查询参数传递复杂数据类型(如JSON)是一个不好的想法,但是“现实世界”中的字符串值通常包含分号,因此转义它们似乎是个好主意。

我会采用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);
    };
});

0
你可以使用encodeURIComponent()方法:
q: encodeURIComponent('sin;sout')

1
这对我们不起作用,Angular 似乎也对字符串进行了编码,因此我们得到的结果是:http://somedomain.com/?q=sin%253Bsout(%253B 应为 %3B) - joente

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接