当不同的组件使用 axiosinstance 调用 API 时,在哪里添加/删除拦截器
我在应用程序启动时初始化了 axios 实例。在 Login.js 下,我能够获取令牌,并希望使用拦截器将其添加到标头,用于大多数后续 api 调用,例如在 AddSampleTable.js 下使用时。(其中一些也需要在没有授权标头的情况下使用,例如 ForgotPassword.js)
目前,我必须对每个组件中的每个 api 调用执行此操作。我当前的代码如下
axios.js
import axios from 'axios';
const baseURL = process.env.REACT_APP_BASE_URL;
let headers = {};
//this never executes since we havent logged in yet
//if(localStorage.token) {
//headers.Authorization = `Bearer ${localStorage.token}`;
//}
const token = localStorage.getItem('token');
const axiosInstance = axios.create({
baseURL: baseURL,
headers: {'Authorization': token? `Bearer ${token}`: null},
});
export default axiosInstance;
Login.js
import axiosInstance from '../../helpers/axios';
const printValues = e =>{
e.preventDefault();
axiosInstance.post('/auth', data)
.then(res =>{
console.log("writing token");
dispatch(jwtTokenRecieved(res.data.token));
localStorage.setItem('token',res.data.token);
const config = {
headers:{
Authorization:'Bearer '+res.data.token
}
}
axiosInstance.get('/User/GetUserByID/0', config)
.then(res =>{
dispatch(isLoggedUser(res.data));
})
.catch(err =>{
console.log(err);
})
AddSampleTable.js
这是我想要使用实例的地方,默认情况下令牌应该存在,但目前我正在从 localstorage 中提取每个 api 调用
import axiosInstance from '../../helpers/axios';
export default function AddSamplesTable(){
const jwtToken = useSelector(state => state?.token?.data || '');
const retrieveSampleData = () =>{
const config = {
headers:{
Authorization:'Bearer '+ jwtToken,
'Content-Type': 'application/json'
}
}
axiosInstance.get('/batch/'+CoCData.id, config)
.then(function (response) {
setSamples(response.data.samples);
})
.catch(function (error) {
console.log(error);
});
}
}
注意我还使用 Reducer 和操作将令牌设置到 localStorage 中,如您所见(除了通过 setItem 保存它)
dispatch(jwtTokenRecieved(res.data.token));
更新:我曾尝试在创建函数后在 axios.js 中使用拦截器,如下所示
axiosInstance.interceptors.request.use(
config => {
console.log(config)
const token = JSON.parse(localStorage.getItem('token'));
config.headers.Authorization = token ? `Bearer ${token}`: null;
return config;
}
);
但是当新用户登录时,现有令牌值不会使用新令牌进行更新,我
获取
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'status')
对安全 API 和访客 API 使用 不同的 Axios 实例
请按照以下步骤操作:
- 为安全和访客 API 定义 baseURL
- 创建不同的 Axios 实例
- 为安全 API Axios 实例定义请求、响应和错误处理程序
- 使用请求处理程序,将令牌放入请求标头中
- 将上述处理程序作为拦截器绑定到安全 Axios 实例
- 导出两个 axios 实例并根据需要使用
- 在注销或使用计时器时清除令牌
axios.js
// /userLibrary/axios.js
import axios from 'axios';
// Step 1
const baseURL = process.env.REACT_APP_BASE_URL;
// Step 2
const guestAxios = axios.create({ baseURL })
const secureAxios = axios.create({ baseURL })
// Step 3: Define handlers
const errorHandler = ()=>{
...
}
const secureAPIRequest= (config)=>{
// Step 4: Put token in header
const token = JSON.parse(localStorage.getItem('token'));
config.headers.Authorization = token ? `Bearer ${token}`: null;
return config
}
const secureAPIResponse= ()=>{
...
}
// Step 5: Add interceptors for secure axios instance
secureAxios.interceptors.request.use(secureAPIRequest, errorHandler)
secureAxios.interceptors.response.use(secureAPIResponse, errorHandler)
// Step 6
export {
guestAxios,
secureAxios
}
axios.js
// /userLibrary/axios.js
import axios from 'axios';
// Step 1
const baseURL = process.env.REACT_APP_BASE_URL;
// Step 2
const guestAxios = axios.create({ baseURL })
const secureAxios = axios.create({ baseURL })
// Step 3: Define handlers
const errorHandler = ()=>{
...
}
const secureAPIRequest= (config)=>{
// Step 4: Put token in header
const token = JSON.parse(localStorage.getItem('token'));
config.headers.Authorization = token ? `Bearer ${token}`: null;
return config
}
const secureAPIResponse= ()=>{
...
}
// Step 5: Add interceptors for secure axios instance
secureAxios.interceptors.request.use(secureAPIRequest, errorHandler)
secureAxios.interceptors.response.use(secureAPIResponse, errorHandler)
// Step 6
export {
guestAxios,
secureAxios
}
Login.js
import { guestAxios } from '/userLibrary/axios.js'
...
AddSampleTable.js
的示例代码
import { secureAxios } from '/userLibrary/axios.js'
...
这是一个固执己见的答案,但我主张将 React 应用的代码分成两个区域:
视图
务必使用 React 样式,其中每个源文件仅包含函数,并遵循 React 最佳实践。
常规代码/API 调用
类通常在这里工作得更好,可以将代码和数据封装在一个实例中。在需要时将
ApiClient
或
LoginClient
实例作为 props 传递。来自视图的 API 调用将始终是一行干净的代码,没有代码重复。
示例代码
请参阅 此 Curity 代码示例 。还要注意,安全相关数据仅存储在内存中,从安全角度来看,这通常更好。本地存储中的令牌具有更大的 XSS 风险。
我建议您阅读 react 和 jwt 的完整示例 然后您可以使用 react-redux-jwt 检查差异>
在 redux 中存储令牌时要小心,每次刷新页面时您都会重新启动 redux 存储,如果您将其作为事实来源,则可能需要每次都重新登录用户(通常是不想要的行为)。 这就是为什么您可以使用 sessionStorage 或 localStorage 或 cookies
sessionStorage(顾名思义)仅在浏览器会话期间可用(并在选项卡或窗口关闭时被删除) - 但它在页面重新加载后仍然存在
localStorage 即使在关闭浏览器并再次打开时也可用,您必须手动或使用 JS 将其删除。
cookies 是另一种选择,它体积更小,在客户端和服务器之间共享,它们在所有请求中传播,它提供了一些过期时间,可以签名或加密。