当不同的组件使用axionsistance调用api时,在哪里添加/删除拦截器



我在应用程序启动时初始化了axios实例。在Login.js下,我可以获得令牌,并希望使用拦截器将其添加到头部,用于大多数后续的api调用,例如在AddSampleTable.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;

登录.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

这是我想要使用实例的地方,默认情况下应该存在令牌,但目前我正在从本地存储中提取每个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);
});
} 

}

注意,我还使用reducers和操作将令牌设置到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;
}
);

但当一个新用户登录时,现有的令牌值不会用新的令牌更新,我会得到

未捕获(承诺中(类型错误:无法读取未定义(读取"状态"(的属性

使用用于安全API和来宾API 的Distinct Axios实例

遵循以下步骤:

  1. 为安全API和来宾API定义baseURL
  2. 创建不同的Axios实例
  3. 为安全的API Axios实例定义请求、响应和错误处理程序
  4. 使用请求处理程序,将令牌放入请求标头中
  5. 将以上处理程序作为拦截器绑定到安全Axios实例
  6. 导出两个axios实例并根据需要使用
  7. 注销或使用计时器时清除令牌

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调用

就将代码和数据封装在一个实例中而言,类在这里通常工作得更好。在需要的地方传递一个ApiClientLoginClient实例作为道具。来自视图的API调用将始终是一个干净的一行代码,没有代码重复。

示例代码

请参阅Curity代码示例。还要注意,与安全相关的数据只存储在内存中,从安全角度来看,这通常更好。本地存储中的令牌具有更大的XSS风险。

我建议您阅读react和jwt的完整示例然后你可以用react redux jwt 检查差异

要小心将您的令牌存储在redux中,每次刷新页面时,您都会重新启动redux存储,如果您将其作为真相的来源,则可能每次都需要重新记录您的用户(通常是不需要的行为(。这就是为什么您可以使用sessionStorage或localStorage或cookie

sessionStorage(顾名思义(只在浏览器会话期间可用(当选项卡或窗口关闭时会被删除(,但它在页面重新加载后仍然有效

localStorage是可用的,即使在关闭浏览器并再次打开时,您也必须手动或使用JS将其删除。

cookie是另一种选择,大小较小,在客户端和服务器之间共享,它们在所有请求中都会传播,它提供了一些到期时间,并且可以签名或添加脚本。

最新更新