【发布时间】:2021-09-08 16:55:35
【问题描述】:
所以这是我的问题。 我在我的项目中使用 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 中将 Content-Type 设置为 'application/json'。
但我的问题是为了上传图片内容类型应该是'multipart/form-data --boundary: set-automatically'。
(注意:手动设置多部分数据的边界似乎不起作用)
如果我们不将 content-type 放在 header 中,则 axios 会自动设置多部分数据的边界。但为此,我必须以某种方式从 axiosInstance 的一个位置(从我上传图像的位置)删除内容类型,而不会干扰项目其他部分使用的 axiosInstance。
我使用 fetch 对其进行了测试,并通过设置新的 axios 实例,它按预期工作。但问题是,如果需要,这些请求不会被 axios 拦截以刷新 JWT 令牌。
我阅读了有关此的各种帖子,但我仍然没有找到解决此问题的方法。
如果需要,我无法提供更多详细信息。请帮帮我,我已经花了 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));
};
但是假设我将核心 axios.js 中的内容类型更改为“multipart/form-data”,它会更改所有请求的内容类型。它会破坏其他东西,但正如预期的那样,它不会解决这个问题。因为设置手动边界似乎不起作用。甚至this 帖子都说要在多部分数据期间删除内容类型,以便由库自动处理(在这种情况下为 axios)
【问题讨论】: