我在我的应用程序中创建了一个检测会话丢失的拦截器(服务器发送HTTP 419)。在这种情况下,我需要从服务器请求一个新会话,然后我想再次自动发送原始请求 也许我可以在请求拦截器中保存请求,然后再次发送它,但可能有一个更简单的解决方案。
请注意,我必须使用特定的Web服务来创建会话。
angular.module('myapp', [ 'ngResource' ]).factory(
'MyInterceptor',
function ($q, $rootScope) {
return function (promise) {
return promise.then(function (response) {
// do something on success
return response;
}, function (response) {
if(response.status == 419){
// session lost
// create new session server-side
// Session.query();
// then send current request again
// ???
}
return $q.reject(response);
});
};
}).config(function ($httpProvider) {
$httpProvider.responseInterceptors.push('MyInterceptor');
});
答案 0 :(得分:21)
这是我对那些感兴趣的人使用承诺的解决方案。基本上,您需要请求新会话,并在发送与原始请求相对应的新请求之前等待响应(使用response.config)。通过返回promise $ http(response.config),您可以确保将响应视为原始请求 (语法可能不是最好的,因为我是承诺的新手)
angular.module('myapp', [ 'ngResource' ]).factory(
'MyInterceptor',
function ($q, $rootScope) {
return function (promise) {
return promise.then(function (response) {
// do something on success
return response;
}, function (response) {
if(response.status == 419){
// session lost
var Session = $injector.get('Session');
var $http = $injector.get('$http');
// first create new session server-side
var defer = $q.defer();
var promiseSession = defer.promise;
Session.query({},function(){
defer.resolve();
}, function(){
// error
defer.reject();
});
// and chain request
var promiseUpdate = promiseSession.then(function(){
return $http(response.config);
});
return promiseUpdate;
}
return $q.reject(response);
});
};
}).config(function ($httpProvider) {
$httpProvider.responseInterceptors.push('MyInterceptor');
});
答案 1 :(得分:19)
responseError
的{{1}}方法必须如下:
httpInterceptor
魔术发生在这里:
responseError: function (response) {
// omit the retry if the request is made to a template or other url
if (response.config.apiCal === true) {
if (response.status === 419) {
var deferred = $q.defer();
// do something async: try to login.. rescue a token.. etc.
asyncFuncionToRecoverFrom419(funcion(){
// on success retry the http request
retryHttpRequest(response.config, deferred);
});
return deferred.promise;
} else {
// a template file...
return response;
}
}
}
答案 2 :(得分:5)
您在正确的道路上,基本上将请求存储在队列中,并在重新建立会话后重试。
查看这个流行的模块:angular http auth(https://github.com/witoldsz/angular-http-auth)。在这个模块中,他们拦截了401个响应,但您可以通过这种方法对解决方案进行建模。
答案 3 :(得分:4)
或多或少相同的解决方案,在typescript中翻译:
/// <reference path="../app.ts" />
/// <reference path="../../scripts/typings/angularjs/angular.d.ts" />
class AuthInterceptorService {
static serviceId: string = "authInterceptorService";
constructor(private $q: ng.IQService, private $location: ng.ILocationService, private $injector, private $log: ng.ILogService, private authStatusService) {}
// Attenzione. Per qualche strano motivo qui va usata la sintassi lambda perché se no ts sbrocca il this.
public request = (config: ng.IRequestConfig) => {
config.headers = config.headers || {};
var s: AuthStatus = this.authStatusService.status;
if (s.isAuth) {
config.headers.Authorization = 'Bearer ' + s.accessToken;
}
return config;
}
public responseError = (rejection: ng.IHttpPromiseCallbackArg<any>) => {
if (rejection.status === 401) {
var that = this;
this.$log.warn("[AuthInterceptorService.responseError()]: not authorized request [401]. Now I try now to refresh the token.");
var authService: AuthService = this.$injector.get("authService");
var $http: ng.IHttpService = this.$injector.get("$http");
var defer = this.$q.defer();
var promise: ng.IPromise<any> = defer.promise.then(() => $http(rejection.config));
authService
.refreshAccessToken()
.then((response) => {
that.$log.info("[AuthInterceptorService.responseError()]: token refreshed succesfully. Now I resend the original request.");
defer.resolve();
},
(err) => {
that.$log.warn("[AuthInterceptorService.responseError()]: token refresh failed. I need to logout, sorry...");
this.authStatusService.clear();
this.$location.path('/login');
});
return promise;
}
return this.$q.reject(rejection);
}
}
// Update the app variable name to be that of your module variable
app.factory(AuthInterceptorService.serviceId,
["$q", "$location", "$injector", "$log", "authStatusService", ($q, $location, $injector, $log, authStatusService) => {
return new AuthInterceptorService($q, $location, $injector, $log, authStatusService)
}]);
希望得到这个帮助。