AngularJS资源:如何禁用url实体编码



在我当前的项目中,我有一个drupal后端,它为我的前端公开rest服务。对我的后端的一些调用实际上并不喜欢对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});
};

调用以下url:

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

有什么建议吗?谢谢

更新:使用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,因为它是角度函数内的局部变量。

因此,我看到的唯一选项是覆盖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);
      }
    };
  });
});

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

自己转换param对象非常简单,这里有一个例子:如何将object序列化为参数列表?

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

现在我还不能真正测试它(如果你能创建一个带有测试用例的jsfiddle供我们使用,那会很有帮助),但你可能应该看看资源对象的transformRequest函数。

来自文档:

transformRequest–{函数(数据,headersGetter)|数组。}–使改变函数或这样的函数的阵列。transform函数http请求正文和标头,并返回其转换后的(通常是序列化的)版本。

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

看起来resourceFactory函数在构建的路由上创建了一个闭包,所以您没有权限更改它。

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

最新更新