Axios 实例在第一次调用时未从本地存储获取令牌 - React js + django

Axios instance not getting the token from local storage on first call - React js + django

我创建了一个 Axios 实例来设置 baseURL 和 headers。 header 还需要包含授权令牌。因此,当用户登录时,我调用 API 来使用 useEffect 获取与用户相关的一些数据。因此 API 在登录完成后立即被调用。此 API 需要权限,因此需要令牌。登录时,我将令牌存储在本地存储中,但由于某种原因,在第一次调用实例时未加载令牌,我从后端收到 Unauthorised 错误。但是如果我手动重新加载页面,API 会再次被调用,但这次实例会收到令牌并获取数据。下面是我的代码。

axios 实例

const baseURL = "http://127.0.0.1:8000";

// getting the token from the localstorage
let authTokens = localStorage.getItem("token")
  ? JSON.parse(localStorage.getItem("token"))
  : null;

const axiosInstance = axios.create({
  baseURL,
  headers: { Authorization: `Bearer ${authTokens?.access}` },
});

api 来电

export const fetchTeacherDetail = async () => {
 
  try {
    let response = await axiosInstance.get(`/teacher/get-detail/`);
    return response;
  } catch (error) {
    ToastNotification(
      "We are facing some errors. Please trying again later.",
      "error"
    );
  }
};

我看了一个 youtube 视频来了解这个,他没有收到这个错误,但由于某种原因我收到了这个错误。请给我建议我该怎么做。

更新

用于显示我在本地存储中存储令牌的位置的代码

在 redux 中存储令牌和用户详细信息的操作

export const loginUser = (email, password) => async (dispatch) => {
  try {
    // before calling the api
    dispatch(loginPending());

    //calling the api
    const response = await userLogin(email, password);
    if (response.status !== 200) {
      return dispatch(loginFail(response.status));
    } else {
      dispatch(loginSuccess(response.data));
    }
  } catch (error) {
    dispatch(loginFail(error.message));
  }
};

userLogin() API 代码

export const userLogin = async (email, password) => {
  const config = {
    headers: {
      "Content-Type": "application/json",
    },
  };

  const body = JSON.stringify({ email, password });

  try {
    const response = await axios.post(`${url}/token/`, body, config);
    if (response.status === 200) {
      localStorage.setItem("token", JSON.stringify(response.data));
      return response;
    }
  } catch (error) {
    ToastNotification("Credentials provided are not valid", "error");
  }
};

response.data 在上述函数中收到的模拟值

 refresh: 'eyJ0eXAiOiJKV1QUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY1ODU4NTUxMSwiaWF0IjoxNjUwODA5NTExLCJqdGkiOiI4NDRjZWFjNTFkOWI0OGNkOWE0MTFlYzU4ZWY4ZDMxYiIsInVzZXJfaWQiOiI0YjdhODEzYmFkYi05VzZXIiOmZhbHNlLCJpc19zdGFmZiI6ZmFsc2V9.zlGb4tPtJ9HlUvSUZW6QrHHfDsUU8hZ6rliYc3RbJXQ',
access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjU4NTg1NTExLCJpYXQiOjEk1MTEsImp0aSI6ImEyYzg1NzAyZmY0ZjQ4YmRiZjEwZjEzNTUwYjk0MzE2IiwidXNlcl9pZCI6lciI6dHJ1Zsc2UsImlzX3N1cGVydXNlciI6ZmFsc2UsImlzX3N0YWZmIjpmYWxzZX0.qrictVbES22dGpA0dpVA5KLTZkrMsCM0hDHq2Yrs

您的问题可能是因为您在应用程序启动时设置了 axios 实例令牌,但从未在登录时更新它。

您需要在登录时通过再次检查 localStorage 数据来“刷新”该值。

一个快速的解决方案是每次调用 API

时计算 headers
const baseURL = "http://127.0.0.1:8000";

export const getToken = () => localStorage.getItem("token")
  ? JSON.parse(localStorage.getItem("token"))
  : null;

export const getAuthorizationHeader = () => `Bearer ${getToken()}`;

export const axiosInstance = axios.create({
  baseURL,
  headers: { Authorization: getAuthorizationHeader() },
});

然后在API调用

export const fetchSomething = async () => {
  try {
    const response = await axiosInstance.get("/foo", { 
      headers: { Authorization: getAuthorizationHeader() }
    });

    return response;

  } catch (error) {
    // error handling
  }
};

另一种解决方案是在登录时通过执行类似这样的操作来改变 axios 实例

axiosInstance.defaults.headers.Authorization = `Bearer ${result.access}`

我相信问题不在后端,因为您需要手动刷新以使授权正常,所以无需担心后端问题是什么,您正在将令牌的值存储在 const getToken 它将永远存储在那里,我的意思是,如果它在开始时将它作为坏令牌或 null 获取,它将始终是相同的初始值,所以你要做的是:

const baseURL = "http://127.0.0.1:8000";

const axiosInstance = axios.create({
  baseURL,
  headers: {
    Authorization: `Bearer ${
      localStorage.getItem("token")
        ? JSON.parse(localStorage.getItem("token")).access
        : null
    }`,
  }
});