Files
storage-service-ui/src/api/HttpAuthAPI.js

113 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import axios from 'axios';
import authServiceApi from './AuthServiceAPI';
import tokenApi from './TokenAPI';
/**
* @interface RequestConfig
* @type {Object}
* @property {MethodType} method - метод запроса
* @property {string} url - адрес запроса
* @property {Object} body - тело запроса
*/
/**
* Api прикрепляет ко всем запросом заголовок с токеном авторизации. В случае, когда сервер
* возвращает ошибку 401 (Не авторизован), пытается рефрешнуть токен. В момент обновления пары токенов
* api сохраняет все запросы в очередь. Если ревреш токенов удался, то запросы будут выполнены
* в том же порядке, как и пришли, либо упадут с ошибкой, если ревреш выполнить не удалось.
* @class HttpAuthApi
*/
class HttpAuthApi {
constructor () {
this.pendingRequests = [];
this.isPendingRefresh = false;
}
/**
* Выполняет какое-то действие над всеми запросами из очереди, пока она не закончится
* @param {Function} handler - функция обработчик запроса
*/
processPendingRequests = (handler) => {
this.isPendingRefresh = false;
while (this.pendingRequests.length) {
const pendingRequest = this.pendingRequests.shift();
handler(pendingRequest);
}
}
/**
* Повторяет все запросы из очереди в порядке их поступления
*/
repeatRequests = () => {
this.processPendingRequests(({resolve, reject, requestConfig}) => {
this.request(requestConfig)
.then(resolve)
.catch(reject);
});
}
/**
* Выбрасывает ошибки для всех запросов из очереди
* @param {axios.error} error - ошибка, которую возвращает axios
*/
rejectRequests = (error) => {
this.processPendingRequests(({reject}) => {
reject(error);
});
}
/**
* Перехватывает ошибку 401 (Не авторизован), другие ошибки выбрасывает дальше
* @param {axios.error} error - ошибка, которую возвращает axios
* @param {Function} resolve - функция промиса, которая разрешает его успешно
* @param {Function} reject - функция промиса, которая завершает его неудачей
* @param {RequestConfig} requestConfig - настройки для выполнения запроса
*/
errorHandling = (error, resolve, reject, requestConfig) => {
if (error.response.status === 401) {
this.isPendingRefresh = true;
this.pendingRequests({resolve, reject, requestConfig});
authServiceApi.refresh()
.then(() => {
this.repeatRequests();
})
.catch((refreshError) => {
this.rejectRequests(refreshError);
/*
* Снять авторизацию и сделать роут
* Сбросить все запросы с ошибкой авторизации
*/
});
} else {
reject(error);
}
}
/**
* Добавляет к запросу токен в качестве заголовка
* @param {RequestConfig} requestConfig - настройки для выполнения запроса
*/
addTokenToRequest = (requestConfig) => ({
...requestConfig,
headers: {
'Authorization': tokenApi.getAccessToken(),
},
})
/**
* Метод для внешнего использования, выполняет запрос к серверу, используя axios
* @param {RequestConfig} requestConfig - настройки для выполнения запроса
*/
request = (requestConfig) => {
return new Promise((resolve, reject) => {
axios(this.addTokenToRequest(requestConfig))
.then((response) => resolve(response))
.catch((error) => this.errorHandling(error, resolve, reject, requestConfig));
});
}
}
const httpAuthApi = new HttpAuthApi();
export default httpAuthApi;