3

在我的 Angular 应用程序中,我有一个$http用于从服务器检索数据的服务。服务器端点使用 HMAC 身份验证,并期望查询字符串参数在 URL 上按特定顺序排列。

Angular$http在构建 URL 时对参数进行排序,因此似乎无法指定自定义参数顺序。

这是一个例子:

this.apiCall = function() {
    return $http({
        method: 'GET',
        url: 'http://example.com/url/v1/endpoint',
        params: {
            'c': 'cdata',
            'a': 'adata',
            'b': 'bdata'
        }
    });
};

Angular 会将 URL 构建为http://example.com/url/v1/endpoint?a=adata&b=bdata&c=cdata,但我需要保留指定的参数顺序,http://example.com/url/v1/endpoint?c=cdata&a=adata&b=bdata.

我意识到我可以手动将参数附加到 URL 字符串,但这不是很友好,而且它不允许在$http拦截器中轻松管理。

Angular 可能会对参数进行排序以保持跨浏览器实现的统一行为,因为 ECMAScript 中没有指定对象排序。

无论如何,有没有人知道如何解决对参数进行排序的默认 Angular 行为,以构建一个保留指定参数的 URL?

4

2 回答 2

3

我改进了您的解决方案,以创建更精简并保证工作的东西:

$httpProvider.interceptors.push(function() {
    return {
        request: function (config) {
            if (!config.paramOrder) {
                return config;
            }

            // avoid leaking config modifications
            config = angular.copy(config, {});

            var orderedParams = [];
            config.paramOrder.forEach(function (key) {
                if (config.params.hasOwnProperty(key)) {
                    orderedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(config.params[key]));
                    // leave only the unordered params in the `params` config
                    delete config.params[key];
                }
            });

            config.url += (config.url.indexOf('?') === -1) ? '?' : '&';
            config.url += orderedParams.join('&');

            return config;
        },
    };
});

使用以下命令调用:

$http({
    method: 'GET',
    url: 'http://example.com/url/v1/endpoint',
    params: {
        a: 'aValue',
        b: 'bValue',
        c: 'cValue'
    },
    paramOrder: ['c', 'a']
});

获取以 key 开头的查询字符串,c后跟a. 中未提及的参数paramOrder将附加在有序参数之后(按字母顺序)。

于 2014-11-25T19:29:05.477 回答
1

我最终创建了一个基本的拦截器来保持“指定的”参数顺序。如果在调用keepParamsOrder中设置了配置变量,则此拦截器运行。$http

在您的模块配置中:

$httpProvider.interceptors.push(function() {
    return {
        'request': function(config) {
            if (!config.keepParamsOrder || !config.params) {
                return config;
            }

            var queryStrings = [];
            for (var key in config.params) {
                if (config.params.hasOwnProperty(key)) {
                    queryStrings.push(key + '=' + config.params[key]);
                }
            }

            // Reset the params to be empty
            config.params = {};

            config.url += (config.url.indexOf('?') === -1) ? '?' : '&';
            config.url += queryStrings.join('&');

            return config;
        },
    };
});

告诉它在服务调用配置中运行:

this.apiCall = function() {
    return $http({
        method: 'GET',
        url: 'http://example.com/url/v1/endpoint',
        params: {
            'c': 'cdata',
            'a': 'adata',
            'b': 'bdata'
        },
        keepParamsOrder: true
    });
};
于 2014-11-25T18:13:57.970 回答