因此,我正在为我的应用程序进行身份验证,我想要完成的任务是为我的 redux thunk 函数提供私有 Axios 实例,以便它们可以发出经过身份验证的请求。我遇到的主要问题是,我想向 Axios 实例配置提供访问令牌(存在于应用程序状态中),但这不起作用,因为它需要钩子,而 Redux 切片中不允许钩子。我尝试使用
store.getState()
直接访问状态,但是商店正在返回 undefined
,而且我也相信如果不使用钩子它就不会更新。我正在尝试提出一个解决方案,但我却一无所获。当然,出于多种原因,我想避免使用本地存储。也请不要建议 RTK-Query。我在下面提供了一些代码:
私有实例.ts
export const privateInstance = axios.create({
baseURL: 'http://localhost:5000',
headers: { 'Content-Type': 'application/json' },
withCredentials: true
});
const refresh = useRefreshToken();
const accessToken = store?.getState().auth.userContext.accessToken;
// Request interceptor for API calls
privateInstance.interceptors.request.use(
async config => {
if (!config.headers['Authorization']) {
config.headers['Authorization'] = `Bearer ${accessToken}`;
config.headers['Accept'] = 'application/json';
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
}
return config;
},
error => {
Promise.reject(error)
});
// Response interceptor for API calls
privateInstance.interceptors.response.use((response) => {
return response
}, async function (error) {
const originalRequest = error.config;
console.log(error)
if (error.response.status === 403 && !originalRequest._retry) {
originalRequest._retry = true;
const access_token = await refresh();
privateInstance.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;
return privateInstance(originalRequest);
}
return Promise.reject(error);
});
useRefreshToken.ts(
instance
只是配置了基本url的标准Axios实例`)
const useRefreshToken = () => {
const refresh = async () => {
try {
await instance({
url: '/auth/refresh',
method: 'GET'
}).then((res) => {
return res.data.accessToken
})
} catch (e: any) {
console.log(e)
}
}
return refresh;
}
export default useRefreshToken;
示例Slice.ts
...
export const addToToDoListAsync = createAsyncThunk(
"todoList/addToToDoListAsync",
async (todoObject: ToDoObject) => {
try {
return privateInstance({
url: '/todoList',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify(todoObject)
}).then((res) => {
return res.data;
})
} catch (e: any) {
console.log(e.response.data.error)
return e;
}
}
)
...
请求失败并显示 403 禁止,因为当前实现未提供访问令牌。除了本地存储和 RTK 查询之外的任何帮助/想法将不胜感激。
要在不使用 hooks 或 RTK-Query 的情况下解决此问题,您可以将访问令牌作为参数传递给 thunk 操作创建者。这样,您可以从组件内的 Redux 状态访问访问令牌,然后在分派 thunk 操作时将其作为参数传递。
以下是如何修改 addToToDoListAsync thunk 操作创建者以接受访问令牌作为参数:
javascript
export const addToToDoListAsync = createAsyncThunk(
"todoList/addToToDoListAsync",
async (payload: { todoObject: ToDoObject, accessToken: string }) => {
const { todoObject, accessToken } = payload;
try {
return privateInstance({
url: '/todoList',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
data: JSON.stringify(todoObject)
}).then((res) => {
return res.data;
})
} catch (e: any) {
console.log(e.response.data.error)
return e;
}
}
)
然后,在组件中分派 addToToDoListAsync 操作时,您可以将访问令牌作为参数传递:
import { addToToDoListAsync } from './exampleSlice';
// Assuming you have access to the access token in your component's props or state
const accessToken = 'your-access-token';
dispatch(addToToDoListAsync({ todoObject: yourTodoObject, accessToken }));
通过这种方式,您可以从组件内的 Redux 状态访问访问令牌,并将其传递给 thunk 操作创建者,从而允许您的私有 Axios 实例发出经过身份验证的请求,而无需依赖钩子或 RTK-Query。