这是我编译的 JavaScript 的视图,我使用了 TypeScript 并提供了该代码。一般来说,我会建议另外两种模式:
- 除了类变量之外,将“refreshTokenInProcess”存储为本地存储变量。这将有助于保持一个单一的持久值,以指示刷新是否正在进行中。
- 跟踪 retryCount 和 maxRetryCount 以确保不会发生循环。如果超过重试次数,您还可以执行其他一些任务。成功刷新后,retryCount 会重置。
JavaScript
var TestServices = /** @class */ (function () {
function TestServices($window, $injector, $http, $q) {
var _this = this;
this.$window = $window;
this.$injector = $injector;
this.$http = $http;
this.$q = $q;
this.tokenRefreshing = function () {
var deferred = _this.$q.defer();
// Run refresh token service only once in case multiple requests are failing
_this.retryCount++;
var refreshToken = _this.$window.localStorage.getItem('refresh_token');
var clientId = _this.$window.localStorage.getItem('client_id');
var apiUrl = _this.$window.localStorage.getItem('apiUrl');
var param = 'grant_type=refresh_token&refresh_token=' + refreshToken + '&client_id=' + clientId;
_this.$http = _this.$http || _this.$injector.get('$http');
_this.$http.post(apiUrl + 'token', param, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).
then(function (success) {
_this.$window.localStorage.setItem('token', success.data.access_token);
_this.$window.localStorage.setItem('refresh_token', success.data.refresh_token);
_this.$window.localStorage.setItem('client_id', 'web');
_this.$window.localStorage.setItem('expires', success.data['.expires']);
_this.refreshTokenInProcess = false;
// reset the retry count
_this.retryCount = 0;
deferred.resolve(success);
}, function (err) {
_this.refreshTokenInProcess = false;
deferred.reject(err);
});
return deferred.promise;
};
}
Object.defineProperty(TestServices.prototype, "refreshTokenInProcess", {
get: function () {
if (this.$window) {
this._refreshTokenInProcess = this.$window.localStorage.getItem('refreshTokenInProcess') === 'true';
}
return this._refreshTokenInProcess === true;
},
set: function (value) {
this._refreshTokenInProcess = value === true;
var strValue = value === true ? 'true' : 'false';
if (this.$window) {
this.$window.localStorage.setItem('refreshTokenInProcess', strValue);
}
},
enumerable: true,
configurable: true
});
TestServices.prototype.executeRequest = function (config) {
var accessToken = this.$window.localStorage.getItem('token');
if (accessToken !== 'null') {
config.headers.authorization = 'bearer ' + accessToken;
}
this.lastRequest = config;
return config;
};
TestServices.prototype.request = function (config) {
return this.executeRequest(config);
};
TestServices.prototype.responseError = function (response) {
var _this = this;
if (response.status === 406 && response.data === 'Unauthenticated Token.') {
// retry logic
if (this.refreshTokenInProcess === false && this.retryCount < this.maxRetryCount) {
this.refreshTokenInProcess = true;
this.tokenRefreshing().then(function () {
return _this.$http(_this.executeRequest(response.config)).then(function (data) {
if (data) {
response.config.callerController(data.data);
}
});
});
}
}
return response;
};
return TestServices;
}());
TypeScript
export class TestServices implements ng.IHttpInterceptor {
private _refreshTokenInProcess: boolean;
get refreshTokenInProcess(): boolean {
if (this.$window) {
this._refreshTokenInProcess = this.$window.localStorage.getItem('refreshTokenInProcess') === 'true';
}
return this._refreshTokenInProcess === true;
}
set refreshTokenInProcess(value: boolean) {
this._refreshTokenInProcess = value === true;
const strValue = value === true ? 'true' : 'false';
if (this.$window) {
this.$window.localStorage.setItem('refreshTokenInProcess', strValue);
}
}
lastRequest: any;
maxRetryCount: 10;
retryCount: 0;
constructor(public $window: ng.IWindowService, public $injector: ng.auto.IInjectorService, public $http: ng.IHttpService, public $q: ng.IQService) {
}
executeRequest(config: ng.IRequestConfig) {
const accessToken = this.$window.localStorage.getItem('token');
if (accessToken !== 'null') {
config.headers.authorization = 'bearer ' + accessToken;
}
this.lastRequest = config;
return config;
}
request(config: ng.IRequestConfig) {
return this.executeRequest(config);
}
tokenRefreshing = () => {
const deferred = this.$q.defer();
// Run refresh token service only once in case multiple requests are failing
this.retryCount++;
const refreshToken = this.$window.localStorage.getItem('refresh_token');
const clientId = this.$window.localStorage.getItem('client_id');
const apiUrl = this.$window.localStorage.getItem('apiUrl');
const param = 'grant_type=refresh_token&refresh_token=' + refreshToken + '&client_id=' + clientId;
this.$http = this.$http || this.$injector.get('$http');
this.$http.post(apiUrl + 'token', param, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).
then((success: any) => {
this.$window.localStorage.setItem('token', success.data.access_token);
this.$window.localStorage.setItem('refresh_token', success.data.refresh_token);
this.$window.localStorage.setItem('client_id', 'web');
this.$window.localStorage.setItem('expires', success.data['.expires']);
this.refreshTokenInProcess = false;
// reset the retry count
this.retryCount = 0;
deferred.resolve(success);
}, (err: any) => {
this.refreshTokenInProcess = false;
deferred.reject(err);
});
return deferred.promise;
}
responseError(response: any) {
if (response.status === 406 && response.data === 'Unauthenticated Token.') {
// retry logic
if (this.refreshTokenInProcess === false && this.retryCount < this.maxRetryCount) {
this.refreshTokenInProcess = true;
this.tokenRefreshing().then(() => {
return this.$http(this.executeRequest(response.config)).then((data: any) => {
if (data) {
response.config.callerController(data.data);
}
});
});
}
}
return response;
}
}