Breeze使用Angular $http拦截器

5

我使用了一个angular $http拦截器来检查ajax请求是否返回401(未经身份验证)。 如果响应是401,则原始请求被排队,显示登录表单,并在成功登录后重试排队的请求。这已经可以使用$http工作,而angular拦截器的源代码如下:

define('common.service.security.interceptor', ['angular'], function() {
'use strict';

angular.module('common.service.security.interceptor', ['common.service.security.retryQueue'])

.factory('securityInterceptor', [
    '$injector',
    '$location',
    'securityRetryQueue',
    function($injector, $location, securityRetryQueue) {

        return function(promise) {

            var $http = $injector.get('$http');


            // catch the erroneous requests
            return promise.then(null, function(originalResponse){
                if(originalResponse.status === 401){
                    promise = securityRetryQueue.pushRetryFn('Unauthorized', function retryRequest(){
                        return $injector.get('$http')(originalResponse.config);
                    });
                }

                 return promise;
            });
        };
    }
])

// register the interceptor to the angular http service. method)
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.responseInterceptors.push('securityInterceptor');

}]);});

我应该如何使用这个angular $http拦截器来发起breeze请求?

Breeze在文件"Breeze/Adapters/breeze.ajax.angular.js"中提供了对angular $http服务的封装。因此,第一个想法是告诉breeze去使用它:

breeze.config.initializeAdapterInstance("ajax", "angular", true);

调试angular.js时,发现breeze实际上使用了$http,但它没有执行上面注册的拦截器。在$http内部,有一个名为"reversedInterceptors"的数组,用于保存已注册的拦截器。我将这个数组记录到控制台中。如果我使用$http,则该数组的长度为1(如预期),但是当使用breeze进行请求时,该数组为空。

问题是,如何在breeze请求中使用此$http拦截器?

以下是由breeze提供的breeze.ajax.angular.js代码:

define('breeze.ajax.angular.module', ['breeze', 'angular'], function (breeze) {
'use strict';
/* jshint ignore:start */
var core = breeze.core;

var httpService;
var rootScope;

var ctor = function () {
    this.name = "angular";
    this.defaultSettings = {};
};

ctor.prototype.initialize = function () {

    var ng = core.requireLib("angular");

    if (ng) {
        var $injector = ng.injector(['ng']);
        $injector.invoke(['$http', '$rootScope',
            function (xHttp, xRootScope) {
                httpService = xHttp;
                rootScope = xRootScope;
        }]);
    }

};

ctor.prototype.setHttp = function (http) {
    httpService = http;
    rootScope = null; // to suppress rootScope.digest
};

ctor.prototype.ajax = function (config) {
    if (!httpService) {
        throw new Error("Unable to locate angular for ajax adapter");
    }
    var ngConfig = {
        method: config.type,
        url: config.url,
        dataType: config.dataType,
        contentType: config.contentType,
        crossDomain: config.crossDomain
    }

    if (config.params) {
        // Hack: because of the way that Angular handles writing parameters out to the url.
        // so this approach takes over the url param writing completely.
        // See: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
        var delim = (ngConfig.url.indexOf("?") >= 0) ? "&" : "?";
        ngConfig.url = ngConfig.url + delim + encodeParams(config.params);
    }

    if (config.data) {
        ngConfig.data = config.data;
    }

    if (!core.isEmpty(this.defaultSettings)) {
        var compositeConfig = core.extend({}, this.defaultSettings);
        ngConfig = core.extend(compositeConfig, ngConfig);
    }

    httpService(ngConfig).success(function (data, status, headers, xconfig) {
        // HACK: because $http returns a server side null as a string containing "null" - this is WRONG.
        if (data === "null") data = null;
        var httpResponse = {
            data: data,
            status: status,
            getHeaders: headers,
            config: config
        };
        config.success(httpResponse);
    }).error(function (data, status, headers, xconfig) {
        var httpResponse = {
            data: data,
            status: status,
            getHeaders: headers,
            config: config
        };
        config.error(httpResponse);
    });
    rootScope && rootScope.$digest();
};

function encodeParams(obj) {
    var query = '';
    var key, subValue, innerObj;

    for (var name in obj) {
        var value = obj[name];

        if (value instanceof Array) {
            for (var i = 0; i < value.length; ++i) {
                subValue = value[i];
                fullSubName = name + '[' + i + ']';
                innerObj = {};
                innerObj[fullSubName] = subValue;
                query += encodeParams(innerObj) + '&';
            }
        } else if (value instanceof Object) {
            for (var subName in value) {
                subValue = value[subName];
                fullSubName = name + '[' + subName + ']';
                innerObj = {};
                innerObj[fullSubName] = subValue;
                query += encodeParams(innerObj) + '&';
            }
        } else if (value !== undefined) {
            query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
        }
    }

    return query.length ? query.substr(0, query.length - 1) : query;
}


breeze.config.registerAdapter("ajax", ctor);

breeze.config.initializeAdapterInstance("ajax", "angular", true);
/* jshint ignore:end */
});
2个回答

6

使用setHttp方法可以让我在breeze angular ajax适配器中使用http拦截器。在我的环境中,代码如下:

(function() {
    'use strict';

    var serviceId = 'entityManagerFactory';
    angular.module('app').factory(serviceId, ['$http', emFactory]);

    function emFactory($http) {

        var instance = breeze.config.initializeAdapterInstance("ajax", "angular");
        instance.setHttp($http);

        ...

    }
})();

我真正找到有关此事的信息仅在1.4.4版本发布说明中,可以在下载页面上找到。我不太理解这是做什么的,相信Breeze团队会有更好的解释。

BINGO!@almaplayer。setHttp FTW。请查看我的回答。 - Ward

4

按照 @almaplayera 的解释,您需要调用 setHttp($http)请将他的回答标记为正确答案。

这是为什么需要这样做的原因。

默认情况下,breeze angular ajax 适配器会使用可用的任何 $http 实例进行初始化。不幸的是,在大多数脚本加载的时候,YOUR APP 的 $http 实例还没有被创建。这只有在您的模块加载后才会发生...而这通常比 breeze 加载要晚得多。

因此,breeze 会启动自己的 $http 实例,并将 angular ajax 适配器连接到该实例上,以避免创建一个完全无法工作的适配器。

如果您的代码没有做任何特殊处理,那么这个方法可以正常工作。虽然它不是最佳选择,但对于大多数人来说都足够了。让我们承认,现在已经有足够多的配置噪音需要处理了。

但是,您正在做一些特殊的处理。您正在配置一个非常具体的 $http 实例,而不是 breeze 为自己创建的实例。

因此,您必须告诉 breeze 使用 YOUR 实例的 $http ... 这就是当您调用 setHttp($http) 时发生的情况。

感谢这个反馈,我已经更新了breeze ajax适配器的文档,以描述如何为Angular应用程序进行配置。

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