这就是我的问题。我在我的项目中使用JWT身份验证,并且在我的react项目中设置了axiosInstance。我还有一个axiosInstance拦截器,负责在需要时拦截和刷新令牌。
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 360000,
transformRequest: [
function (data, headers) {
const accessToken = window.localStorage.getItem('access_token');
if (accessToken) {
headers['Authorization'] = `Bearer ${accessToken}`;
} else {
delete headers.Authorization;
}
return JSON.stringify(data);
},
],
headers: {
'Content-Type': 'application/json',
accept: 'application/json',
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
console.log(
'Caught the error response. Here is your request ',
originalRequest,
);
// case 1: No error specified Most likely to be server error
if (typeof error.response === 'undefined') {
// Uncomment this later
alert('Server error occured');
return Promise.reject(error);
}
// case 2: Tried to refresh the token but it is expired. So ask user to login again
if (
error.response.status === 401 &&
originalRequest.url === baseURL + 'auth/api/token/refresh/'
) {
store.dispatch(setLoginFalse());
return Promise.reject(error);
}
// Case 3: Got 401 Unauthorized error. There are different possiblities
console.log('Error message in axios = ', error.response.data);
if (
error.response.status === 401 &&
error.response.statusText === 'Unauthorized'
) {
const refreshToken = localStorage.getItem('refresh_token');
console.log('Refresh token = ', refreshToken);
// See if refresh token exists
// Some times undefined gets written in place of refresh token.
// To avoid that we check if refreshToken !== "undefined". This bug is still unknown need to do more research on this
if (refreshToken !== undefined && refreshToken !== 'undefined') {
console.log(typeof refreshToken == 'undefined');
console.log('Refresh token is present = ', refreshToken);
const tokenParts = JSON.parse(atob(refreshToken.split('.')[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
// Case 3.a Refresh token is present and it is not expired - use it to get new access token
if (tokenParts.exp > now) {
return axiosInstance
.post('auth/api/token/refresh/', { refresh: refreshToken })
.then((response) => {
localStorage.setItem('access_token', response.data.access);
axiosInstance.defaults.headers['Authorization'] =
'Bearer ' + response.data.access;
originalRequest.headers['Authorization'] =
'Bearer ' + response.data.access;
console.log('access token updated');
// After refreshing the token request again user's previous url
// which was blocked due to unauthorized error
// I am not sure by default axios performs get request
// But since we are passing the entire config of previous request
// It seems to perform same request method as previous
return axiosInstance(originalRequest);
})
.catch((err) => {
// If any error occurs at this point we cannot guess what it is
// So just console log it
console.log(err);
});
} else {
// Refresh token is expired ask user to login again.
console.log('Refresh token is expired', tokenParts.exp, now);
store.dispatch(setLoginFalse());
}
} else {
// refresh token is not present in local storage so ask user to login again
console.log('Refresh token not available.');
store.dispatch(setLoginFalse());
}
}
// specific error handling done elsewhere
return Promise.reject(error);
},
);
export default axiosInstance;
注意,我在axiosIntance中将内容类型设置为“application/json”。
但我的问题是,为了上传图像,内容类型应该是“multipart/form-data --boundary:自动设置“。
(NOTE:手动设置多部分数据的边界似乎不起作用)
如果我们不把content-type放在header中,那么多部分数据的边界是由axios自动设置的,但为此我必须在一个地方(我上传图像的地方)从axiosInstance中删除content-type,而不干扰项目其他部分使用的axiosInstance。
我用fetch测试了它,通过设置新的axios示例,它可以按预期工作,但问题是如果需要刷新JWT令牌,这些请求不会被axios拦截。
我读了很多关于这个问题的帖子,但我仍然没有找到解决这个问题的方法。
我不能提供任何更多的细节,如果需要的话。请帮助我,我已经花了8个多小时调试这个。
谢谢你。
编辑1
我将handleSubmit函数更改为
const handleSubmit = (e) => {
e.preventDefault();
console.log(file);
let formData = new FormData();
formData.append('profile_pic', file);
formData.append('name', 'root');
axiosInstance.defaults.headers.common['Content-Type'] =
'multipart/form-data';
axiosInstance
.put('/users/profile-pic-upload/', formData)
.then((res) => console.log(res))
.catch((err) => console.log(err));
};
但是内容类型仍然是application/json x1c 0d1x
但是让我们假设我在核心axios.js中将内容类型更改为“multipart/form-data”,它会更改所有请求的内容类型。它会破坏其他东西,但正如预期的那样,它不会修复这个问题。因为设置手动边界似乎不起作用。甚至this帖子也说在多部分数据期间删除内容类型,以便由库(在本例中为axios)自动处理。
4条答案
按热度按时间svmlkihl1#
要向axios示例传递任何动态信息,请使用如下返回axios示例的函数:
现在,您可以使用如下axio:
ego6inou2#
或者
请为您的特定示例尝试此操作。
chhqkbe13#
上面来自Lovlesh Pokra的Answer帮助了我。
在我下载文件时检查访问令牌的情况下,需要解析响应以获取新的访问令牌。但是,由于此拦截器位于用于下载文件的类中,并且在创建时将responseType设置为arrayBuffer
我不得不将responseType更改为json,如下所示
然后将其设置回arraybuffer -以便文件下载可以继续
根据您的需要--就在呼叫之前--可以按照您的要求进行更改。
mitkmikd4#
我也在为上传媒体到服务器而挣扎。因为我的全局Axios示例的内容类型为“application/json”,所以当发出请求时,我使用下面的脚本将内容类型更新为“multipart/form-data”。
由于“网络”选项卡中的请求标头仍包含全局配置中的“application/json”,因此仍未更新(这可能是原因-全局标头保存在其他引用中,我们正在其他引用中更新它)
因此,修复方法是在请求传输之前拦截请求,然后按如下所示修改标头
一旦设置了内容类型“multipart/form-data”,Axios将自动处理边界
希望这对你或别人有帮助。谢谢!
快乐编码:-)