Error with axios: TypeError: Cannot read property 'status' of undefined

Viewed 19527

Ok, I have an interceptors in my index.js to refresh the token if the status code is 401, this works fine, but in login page if I return another status code from the server, the messages errors in the page not working, because the axios interceptors not receive a 401.

But if receive a 401, the interceptors work fine.

This is a screenshot about that. It returns a 404 from the server if not found the user. enter image description here

The error is related with Login.vue, but if I delete the axios.interceptors in my index.js the "status" in Login.vue it works fine.

Interceptors

axios.interceptors.response.use(response => {
  return response;
}, error => {
  if (error.response.status === undefined) {
    return;
  } else {
    const code = error.response.status;
    if (code === 401) {
      localStorage.removeItem("token");
      axios.get("token/refresh", {
        params: {
          correo: window.localStorage.getItem("email")
        }
      }).then(response => {
        var refresh_token = response.data.token;
        localStorage.setItem("token", refresh_token);
      }).catch(error => {
        const response = error.response;
        console.log(response.data.errors);
      })
      return Promise.reject(error);
    }
  }
});

I tried in the interceptors, to use something like this:

if(error.response.status == undefined) return;

But it doesn't work.

Login Catch

          .catch(error => {
        this.loading = false;
        if (error.response.status != null) {
          switch (error.response.status) {
            case 400:
              this.alertError = true;
              this.errorMessage = "No estás autorizado para acceder.";
              this.loading = false;
              break;
            case 500:
              this.alertError = true;
              this.errorMessage =
                "Hay un problema con el servidor, disculpa las molestias.";
              this.loading = false;
              break;
            case 404:
              this.alertError = true;
              this.errorMessage = "Vuelve a ingresar tu contraseña";
              break;
            default:
              this.alertError = true;
              this.errorMessage =
                "Hay un error interno en el servidor, intenta de nuevo más tarde";
          }
        }
      })

How to handle this?

2 Answers

A response interceptor must return a response, a resolved promise or a rejected promise.

Your interceptor has logic paths that don't return anything, hence your problem.

You want something like this...

axios.interceptors.response.use(
  (r) => r,
  (error) => {
    if (error.response.status === 401) {
      localStorage.removeItem("token");
      // make sure to return the new promise
      return axios
        .get("token/refresh", {
          params: {
            correo: window.localStorage.getItem("email"),
          },
        })
        .then((response) => {
          localStorage.setItem("token", response.data.token);
          // now replay the original request
          return axios.request(error.config);
        });
    }
    // not a 401, simply fail the response
    return Promise.reject(error);
  }
);

From your implementation, you are trying to refresh the token. What you can do is to shift the refresh token handling to the server side. So If the token expires the server will send the token in the header and inside the axios interceptors write a code as follows to update the local storage when the header contains auth token. Below a sample implementation from my side project

export default () => {
const authTokenJson = localStorage.getItem('auth');

let axiosInstance = null;

if (authTokenJson) {
    const tokens = JSON.parse(authTokenJson);
    axiosInstance = axios.create({
        headers: {
            'authorization': `Bearer ${tokens.token}`,
            'refresh-token': `${tokens.refreshToken}`
        }
    });
} else {
    axiosInstance = axios.create();
}

axiosInstance.interceptors.response.use(
    response => {
        console.log(response);
        const tokens = {
            token: response.headers['authorization'],
            refreshToken: response.headers['refresh-token']
        };
        if (tokens.token && tokens.refreshToken) {
            setTokens(JSON.stringify(tokens));
        }
        return response;
    },
    err => {
        if (err.response.status === 401) {
            EventBus.$emit('errors:401');
        }
        return Promise.reject(err);
    }
);
return axiosInstance;
};
Related