使用 React-Router-Native 从 React Native 中的 Axios 拦截器(组件外部)重定向到查看组件
Redirect to View Component from an Axios interceptor (outside of a component) in React Native with React-Router-Native
我正在开发一项服务 class 以创建 Axios 实例(在 React Native 中),我在其中使用一些拦截器注入 JWT 令牌以针对 API 进行身份验证。
当应用程序检测到access token
过期时,自动使用refresh token
同时请求新令牌和新刷新令牌。
问题是刷新令牌因不活动而过期。
我想在刷新令牌过期时将用户重定向到登录视图组件。
考虑到服务 class 是无状态的并且不关心它是从哪个组件调用的,我需要做什么才能重定向到我的登录视图组件?
这是我目前所拥有的:
//API.js
import axios from 'axios';
import TokenStorage from './TokenStorage';
const API = axios.create({
responseType: 'json',
});
...
API.interceptors.response.use((response) => {
// Return a successful response back to the calling service
return response;
}, (error) => {
// Return any error which is not due to authentication back to the calling service
...
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
// TODO - Redirect to the "/login" route [Login View Component]
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}
// Try request again with new token
...
});
export default API;
环境:
"axios": "^0.19.0",
"react": "16.9.0",
"react-native": "0.61.2",
"react-router-native": "^5.1.2"
PS:这是一个与非常相似的问题,但我需要一个使用 React Router Native 的解决方案。
编辑 1:
我已经尝试使用 "history": "^4.10.1"
包,但没有成功:
// API.js
import {createMemoryHistory} from 'history';
const history = createMemoryHistory();
...
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
history.push('/login'); // This don't work!
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}
没有 Redux
//EventPublisher.js
export default class EventPublisher {
static instance;
listeners = {};
constructor(validEvents){
validEvents.forEach(ve=>{
this.listeners[ve] = []
})
}
subscribe(event, listener){
if(!this.listeners[event]) throw 'Invalid event'
this.listeners[event].push(listener)
return ()=>{
this.listeners[event].remove(listener)
}
}
publish(event){
this.listeners[event].forEach(l=>l())
}
}
在你的顶级组件中
componentDidMount(){
EventPublisher.instance = new EventPublisher([
'REFRESH_TOKEN',
])
this.cancelEventSubscription = EventPublisher.instance.subscribe('REFRESH_TOKEN', ()=>{
//Logic of react router native to navigate to LoginScreen
})
}
componentWillUnmount(){
this.cancelEventSubscription()
}
在 axios 中
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
// TODO - Redirect to the "/login" route [Login View Component]
EventPublisher.instance.publish('REFRESH_TOKEN')
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}
我正在开发一项服务 class 以创建 Axios 实例(在 React Native 中),我在其中使用一些拦截器注入 JWT 令牌以针对 API 进行身份验证。
当应用程序检测到access token
过期时,自动使用refresh token
同时请求新令牌和新刷新令牌。
问题是刷新令牌因不活动而过期。
我想在刷新令牌过期时将用户重定向到登录视图组件。
考虑到服务 class 是无状态的并且不关心它是从哪个组件调用的,我需要做什么才能重定向到我的登录视图组件?
这是我目前所拥有的:
//API.js
import axios from 'axios';
import TokenStorage from './TokenStorage';
const API = axios.create({
responseType: 'json',
});
...
API.interceptors.response.use((response) => {
// Return a successful response back to the calling service
return response;
}, (error) => {
// Return any error which is not due to authentication back to the calling service
...
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
// TODO - Redirect to the "/login" route [Login View Component]
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}
// Try request again with new token
...
});
export default API;
环境:
"axios": "^0.19.0",
"react": "16.9.0",
"react-native": "0.61.2",
"react-router-native": "^5.1.2"
PS:这是一个与
编辑 1:
我已经尝试使用 "history": "^4.10.1"
包,但没有成功:
// API.js
import {createMemoryHistory} from 'history';
const history = createMemoryHistory();
...
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
history.push('/login'); // This don't work!
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}
没有 Redux
//EventPublisher.js
export default class EventPublisher {
static instance;
listeners = {};
constructor(validEvents){
validEvents.forEach(ve=>{
this.listeners[ve] = []
})
}
subscribe(event, listener){
if(!this.listeners[event]) throw 'Invalid event'
this.listeners[event].push(listener)
return ()=>{
this.listeners[event].remove(listener)
}
}
publish(event){
this.listeners[event].forEach(l=>l())
}
}
在你的顶级组件中
componentDidMount(){
EventPublisher.instance = new EventPublisher([
'REFRESH_TOKEN',
])
this.cancelEventSubscription = EventPublisher.instance.subscribe('REFRESH_TOKEN', ()=>{
//Logic of react router native to navigate to LoginScreen
})
}
componentWillUnmount(){
this.cancelEventSubscription()
}
在 axios 中
if (error.config.url === '/tokens/refresh/' || error.response.data.code === 'access_invalid') {
TokenStorage.cleanStorage();
// TODO - Redirect to the "/login" route [Login View Component]
EventPublisher.instance.publish('REFRESH_TOKEN')
return new Promise((resolve, reject) => {
reject(error);
});
} else if (error.config.url === '/tokens/') {
// Reject if user credentials are wrong
return new Promise((resolve, reject) => {
reject(error);
});
}