#vue.js #axios #vuex
Вопрос:
Я не могу заставить две вещи работать вместе-что-то насчет состояния гонки в том, как мои обещания axios улавливают ошибки? Вот подробности:
(1) Когда срок действия токена JWT пользователя истекает, мои API возвращают 401, и перехват axios направляет пользователя на выход из системы.
В main.js
createApp(App)
.use(store)
.use(router)
.mount('#app')
В routes.js
import axios from "axios";
import {createRouter, createWebHistory} from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {requiresAuth: false}
},..]
...
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
axios.interceptors.response.use(response => {
return response;
}, error => {
if (error.response.status === 401) {
console.log('token expired',error.response)
/* THIS WORKS BUT BREAKS THE LOGIN ERROR HANDLING */
}
return Promise.reject(error);
});
Это работает, за исключением того, что оно ломается:
(2) если пользователь входит в систему с неправильными учетными записями, API входа в систему сервера ТАКЖЕ возвращает 401, и мое приложение отображает сообщение об ошибке.
Логин пользователя.vue
methods: {
login() {
this.$store
.dispatch('login', {
username: this.username,
password: this.password
})
.then(() => {
this.$router.push({ name: 'EventList' })
})
.catch(err => {
console.log(err)
this.error = err.response.data.detail
})
}
}
В моем магазине Vuex
store.js
login({ commit }, credentials) {
return axios
.post('//localhost:9000/api/login/', credentials)
.then(({ data }) => {
commit('SET_LOGIN_DATA', data)
})
Я могу заставить работать одно или другое (либо правильно обработать ошибку входа в систему, либо правильно обработать ошибку истечения срока действия токена JWT), но не то и другое. Попытка перехвата axios попадает туда первой и пытается направить пользователя на выход из системы, и все запутывается. Есть идеи, что я делаю не так?
Ответ №1:
Я решил аналогичную проблему (может быть, ту же самую?), настроив свой перехватчик как функцию, которая принимает router
параметр и использует метаданные на моих маршрутах, как это:
Interceptor.js
export default router => {
// In your interceptor error handler callback
if (is401 amp;amp; router.currentRoute.meta.requiresAuth === true) {
// Redirect to logout
}
}
main.js
import registerInterceptor from './path/to/interceptor.js'
// Initialize router and other stuff
// Register the interceptor in created() lifecycle method
new Vue({
router,
store,
created () {
registerInterceptor(this.$router)
},
render: h => h(App)
}).$mount('#app')
Затем, когда я определяю свои маршруты, я добавляю meta
свойство, подобное этому:
// Some routes
{
path: '/secure-route',
name: 'secureRoute',
component: ...,
meta: {
requiresAuth: true
}
}
Затем перехватчик перенаправляет только в том случае, если маршрут требует аутентификации. Вы можете инвертировать его и назвать мета-свойство skipLogoutRedirect
, а в перехватчике просто перенаправить, если skipLogoutRedirect === false
, поэтому вам не нужно определять новое meta.requiresAuth: true
на всех ваших безопасных маршрутах, а вместо этого определять только meta.skipLogoutRedirect: true
маршрут входа в систему.
Дайте мне знать, если это недостаточно ясно, и я могу попытаться добавить больше деталей.
Комментарии:
1. Спасибо-я вижу, что это правильный способ сделать это, и добавил атрибуты аутентификации в свои маршруты, но по какой-то причине я не могу получить доступ
router.currentRoute.meta.requiresAuth
к обработчику перехвата. >Ошибка типа: Не удается прочитать свойство «requiresAuth» неопределенного2. Как вы инициализировали маршрутизатор, а затем настроили свой перехватчик?
3. Я только что обновил ответ. Посмотрите этот
main.js
раздел еще раз и посмотрите, исправит ли это проблему. Я просто понял, что изначально не включал эту деталь.4. Привет! Я обновил q, указав, как я инициализирую. Я использую синтаксис Vue 3, и это сбивает меня с толку, как я делаю то, что вы написали, используя новый стиль инициализации Vue 3.
5. Ваш перехватчик должен быть определен в своем собственном файле. Затем, где бы вы ни монтировали само приложение Vue, вы можете вызвать эту функцию перехватчика и передать экземпляр маршрутизатора. ИЛИ , похоже, вы должны быть в состоянии использовать
router
, так как ваш перехватчик определен ниже, гдеrouter
он был создан.