【问题标题】:AngularJS resource: how to disable url entity encodingAngularJS 资源:如何禁用 url 实体编码
【发布时间】:2014-04-08 18:08:53
【问题描述】:

在我当前的项目中,我有一个 drupal 后端,它为我的前端公开了休息服务。 对我的后端的一些调用并不真正喜欢对 url 实体进行编码。

所以我的问题是:如何禁用某些参数的 URL 编码?

例子:

我需要在不同的搜索词之间使用“+”号来调用我的后端。像这样:

http://backend.com/someservice/search/?terms=search+terms+here

但是有角度,设置如下:

var resource = $resource(
  backendUrl + '/views/:view', {},
    {
      'search': {params:{view:'searchposts'}, isArray:true}
    }
 );

// search posts for the given terms
this.searchPosts = function(terms, limit) {
  resource.search({search:terms.join('+'), limit:limit});
};

调用以下网址:

http://backend.com/someservice/search/?terms=search%2Bterms%2Bhere

有什么建议吗?谢谢!

【问题讨论】:

  • 别打了。只需使用decodeURIComponent() 取回+
  • 由 rfc uris 应该被编码。在服务器上解码。
  • 如果我没有或无法访问服务器怎么办?如果服务器是一些无法更改的外部系统怎么办?不是真正的解决方案...

标签: javascript angularjs rest


【解决方案1】:

更新:使用 Angular 1.4 中的新 httpParamSerializer,您可以编写自己的 paramSerializer 并设置 $httpProvider.defaults.paramSerializer

以下内容仅适用于 AngularJS 1.3(及更早版本)。

不改变AngularJS的源是不可能的。

这是由 $http 完成的:

https://github.com/angular/angular.js/tree/v1.3.0-rc.5/src/ng/http.js#L1057

function buildUrl(url, params) {
      if (!params) return url;
      var parts = [];
      forEachSorted(params, function(value, key) {
        if (value === null || isUndefined(value)) return;
        if (!isArray(value)) value = [value];

        forEach(value, function(v) {
          if (isObject(v)) {
            v = toJson(v);
          }
          parts.push(encodeUriQuery(key) + '=' +
                     encodeUriQuery(v));
        });
      });
      if(parts.length > 0) {
        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
      }
      return url;
}

encodeUriQuery 使用标准 encodeUriComponent (MDN) 将“+”替换为“%2B”

很遗憾,您无法覆盖 encodeUriQuery,因为它是 angular 函数中的局部变量。

所以我看到的唯一选择是覆盖window.encodeURIComponent。我已经在 $http 拦截器中完成了它以尽量减少影响。请注意,原始函数仅在响应返回时才被放回,因此当您的请求正在进行时,此更改是全局的 (!!)。因此,请务必测试这是否不会破坏您应用程序中的其他内容。

app.config(function($httpProvider) {
  $httpProvider.interceptors.push(function($q) {
    var realEncodeURIComponent = window.encodeURIComponent;
    return {
      'request': function(config) {
         window.encodeURIComponent = function(input) {
           return realEncodeURIComponent(input).split("%2B").join("+"); 
         }; 
         return config || $q.when(config);
      },
      'response': function(config) {
         window.encodeURIComponent = realEncodeURIComponent;
         return config || $q.when(config);
      }
    };
  });
});

【讨论】:

  • 该死,我有什么选择? :p
  • 感觉有点笨拙,但嘿似乎工作正常:p 非常感谢!
  • 创建了一个 github 问题以了解还有哪些其他选项:github.com/angular/angular/issues/1339
  • 知道如何编写自己的 paramSerializer 函数吗?到目前为止,我没有运气。现在我正在尝试将参数传递给我的 REST api 的 GET 请求,它正在编码我的问号并中断请求。你的帖子是我最接近可能对我有用的东西,但我不明白如何编写一个函数来阻止该字符被编码:(
【解决方案2】:

AngularJS 仅在您将参数作为额外对象传递时才运行 encodeUriQuery 方法。如果您手动创建自己的参数字符串并将其连接到您的 URL,那么 Angular 将不会修改它。

自己转换 param 对象很简单,下面是一个例子:How to serialize an Object into a list of parameters?

【讨论】:

    【解决方案3】:

    虽然通常您不想这样做(因为在服务器端,您可以使用 URL 解码功能对请求 URI 进行解码以取回您的加号),但有时我们想“打破”规则。

    现在我无法实际测试它(如果您可以创建一个带有测试用例的 jsfiddle 供我们使用,这将很有帮助)但您可能应该看看 transformRequest function of the resource object

    来自文档:

    transformRequest – {函数(数据, headersGetter)|Array.} – 变换 函数或此类函数的数组。变换函数采用 http 请求正文和标头并返回其转换后的 (通常是序列化的)版本。

    【讨论】:

    • 你不能从transformRequest更改网址
    【解决方案4】:

    看起来$resource 代码将此功能包装在Route.prototype.setUrlParams 中:

      params = params || {};
      forEach(self.urlParams, function (_, urlParam) {
        val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
        if (angular.isDefined(val) && val !== null) {
          encodedVal = encodeUriSegment(val);
          url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function (match, p1) {
            return encodedVal + p1;
          });
        } else {
          url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function (match,
              leadingSlashes, tail) {
            if (tail.charAt(0) == '/') {
              return tail;
            } else {
              return leadingSlashes + tail;
            }
          });
        }
      });
    

    Source

    看起来resourceFactory 函数在构造的路由上创建了一个闭包,因此您无权更改它。

    您是否特别需要将其作为资源对象?如果没有,您可以创建一个普通的 $http 调用并使用 Antonio 提到的请求转换。

    【讨论】:

      猜你喜欢
      • 2014-11-09
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 2013-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多