import axios from "axios";
import jwt_decode from "jwt-decode"; // необходимо установить пакет jwt-decode
/**
* Префикс API-роутов
*/
const axiosInstance = axios.create({
baseURL: "/api/"
});
/**
* Роуты, которые не требуют авторизацию.
*/
function noAuthRoute(uri) {
return /^(auth\/|password\/|register$)/.test(uri);
}
/**
* Начало отправки запроса:
* проверка просрочки токена, выдача нового перед отправкой запроса
*/
axiosInstance.interceptors.request.use(async function (config) {
return new Promise(async resolve => {
// все запросы, где не нужна авторизация, пропускаем без доп. обработки
// например, запрос на авторизацию
if (noAuthRoute(config.url)) {
resolve(config);
return;
}
try {
/**
* Тут используется Vuex, через который получаем объект пользователя user,
* в котором содержится access_token.
* Поправьте реализацию под свой код.
*/
let user = window.app.$store.state.auth.user;
let payload = jwt_decode(user.access_token);
/**
* Получаем текущее время и время устаревания токена
*/
let expTime = payload.exp * 1000;
let curTime = new Date().getTime();
/**
* Сравниваем, если разница более 3 секунд - запускаем процедуру получения нового токена из refresh_token
* Доработайте эту часть под свой код.
*/
if (expTime - curTime <= -3000) {
await window.app.$store.dispatch("auth/refreshToken");
}
/**
* Авто-добавление заголовков авторизации.
* Тут также используется Vuex, доработайте под свой код.
*/
config.headers = {...config.headers, ...window.app.$store.getters["auth/authHeader"]};
resolve(config);
} catch (err) {
console.log("axiosInstance.interceptors.request.use", err);
resolve(config);
}
});
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
/**
* Получение ответа:
* если запрос отправлен, но сервер все равно вернул 401 - показываем модальное окно повторного входа
*/
axiosInstance.interceptors.response.use(function (response) {
/**
* Любой код состояния, находящийся в диапазоне 2xx, вызывает срабатывание этой функции.
* Тут можно что-то сделать.
*/
return response;
}, function (error) {
/**
* Любые коды состояния, выходящие за пределы диапазона 2xx, вызывают срабатывание этой функции.
* Тут можно что-то сделать.
*/
try {
if (noAuthRoute(error.response.config.url)) {
return Promise.reject(error);
}
/**
* Тут вызывается модальное окно для повторно ввода логина-пароля.
*/
if (error.response.status === 401) {
window.app.$refs.refreshTokenModal.show({
});
}
} catch (e) {
}
return Promise.reject(error);
});
export default axiosInstance;
如何使用这个模块?您可以直接:
import axios from "../axios";
// ...
axios.get(...
axios.post(...
但是,最好制作单独的服务并已经使用它们。
例如,可以这样获取公司列表:
import CompanyService from "../services/CompanyService";
// ...
let resp = await CompanyService.getTransporterCompanies();
import axios from "../axios";
class CompanyService {
// Список компаний
getTransporterCompanies() {
return axios.get("company?perPage=1000&filter[contractorType.slug]=transporter&fields[company]=id,name");
}
// Блокировка компании
block(id, data) {
return axios.post(`company/${id}/block`, data);
}
}
export default new CompanyService();
Axios 有Interceptors,通过它你可以捕捉到请求发送的那一刻。
此时可以添加授权头,因此只在一个地方完成,而不是分散在使用 axios 的代码中(DRY)。您还可以检查令牌是否已腐烂并请求新令牌。
我曾经以这个片段为基础,并将我的实现作为一个模块。
使用 Axios 的模块
axios/index.js:如何使用这个模块?您可以直接:
但是,最好制作单独的服务并已经使用它们。
例如,可以这样获取公司列表:
比一堆 axios 操作更好阅读?我想是的。这是服务本身,其中隐藏了背面的工作
CompanyService.js:理论。
与访问和更新的令牌一起,令牌的有效期也随之而来。通常在键
exp或下expire。这是访问令牌的到期时间。为了赶上更换的时刻,您只需将 now 时间与 key 下指定的时间进行比较
exp。同时,为了不赶上秒,可以设置一定的偏差。例如,如果现在与指定时间的时间差exp小于 2 分钟,则请求新的令牌