Good evening everyone, here I have a problem with my interceptor in VueJS. I don't understand where my problem comes from, and I'm pulling my hair out...
I've watched several tutorials, I've watched several topics on stackoverflow, but I don't understand what's going on at all.
When I put a debugger on, it's triggered, but when I switch to "axios.interceptors" it tells me that axios is undefined, it's incomprehensible...
import axios from 'axios';
debugger;
axios.interceptors.response.use(function (response) {
console.log(response);
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
console.log(error);
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
const token = localStorage.getItem('token');
export default axios.create({
baseURL: process.env.VUE_APP_URL_API,
headers: {
Authorization: `Bearer ${token}`
}
})
The code above is called in my VueX Store.
import Http from "../../api/http";
export default {
state: {
customers: {},
customer: {},
},
getters: {
customers: state => state.customers,
},
mutations: {
SET_CUSTOMERS(state, customers) {
state.customers = customers;
}
},
actions: {
loadCustomers({commit}) {
Http.get('/customers').then(result => {
commit('SET_CUSTOMERS', result.data.data );
}).catch(error => {
throw new Error(`API ${error}`);
});
}
}
};
I want to trigger http code 401 to logout my user and destroy the token in the browser.
If anyone could help me, I would be delighted, thank you very much.
Regards,
Christophe
As shown in the interceptor docs, just below the example interceptors, if you use an instance, you have to add the interceptor to it:
import axios from 'axios';
const token = localStorage.getItem('token');
const instance = axios.create({
baseURL: process.env.VUE_APP_URL_API,
headers: {
Authorization: `Bearer ${token}`
}
})
instance.interceptors.response.use(function (response) {
console.log(response);
// Any status code within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
console.log(error);
// Any status codes outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
export default instance;
For people which are wondering how the issue has been solved, there is my code :)
success.js
export default function (response) {
return response
}
failure.js
import router from 'vue-router'
export default function (error) {
switch (error.response.status) {
case 401:
localStorage.removeItem('jwt.token')
router.push({
name: 'Login'
})
break
}
return Promise.reject(error)
}
adding this to main.js
const token = localStorage.getItem('jwt.token')
if (token) {
axios.defaults.headers.common.Authorization = token
}
create api.js which is my client for all the request, so my request are always passing by this.
import axios from 'axios'
import success from '#/interceptors/response/success'
import failure from '#/interceptors/response/failure'
const api = axios.create({
baseURL: process.env.VUE_APP_URL_API
})
api.interceptors.request.use((config) => {
const token = localStorage.getItem('jwt.token')
config.headers.Authorization = `Bearer ${token}`
return config
})
api.interceptors.response.use(success, failure)
export default api
I hope it will be usefull :)
Related
await axios
.post(
executeBatch,
{
headers: {
"Content-Type": "application/json",
"x-access-token": localStorage.getItem("token"),
},
}
)
.then(
(response) =>
this.$store.commit(
"insertOutputFile",
response.data.outputFile._id
),
);
alert("You can download the result");
so sometimes i get empty response with status code 200,
was thinking about retrying the request if that happens,
am wondering what is the correct way to approach this issue.
I think axios interceptors will work for you.
axios.interceptors.response.use((response) => {
return response
},
async function(error) {
const originalRequest = error.config;
if () { // condition
originalRequest._retry = true;
}
}
)
You can create setupAxios file in your base redux directory and export it from index.js in your base redux directory.
export {default as setupAxios} from "./setupAxios";
And define setupAxios from your root index.js file
import * as _redux from "./redux";
_redux.setupAxios(axios, store);
Btw, I am using react.js, it could be a little different in vue.js.
I have a problem on using the axios interceptor in my react app. I want to achieve putting the header token just once in my react app. So thats why Im putting it in the interceptor. At the same time, i also want to have just one declaration to get the error. So i dont need to show the error in every page. I’m wondering if i’m using it correctly in my code below? Is there a way that i can shorten it cause i’m declaring it twice for response and request?
export function getAxiosInstance() {
if (axiosInstance === null) {
axiosInstance = axios.create({
baseURL: API_URL,
});
}
axiosInstance.interceptors.request.use(
(config) => {
if (config.baseURL === API_URL && !config.headers.Authorization) {
const token = store.getState().auth.access_token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
console.log(config);
}
}
return config;
},
(error) => {
console.log(error);
store.dispatch(setAPIErrorMessage(error.message));
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.use(
(config) => {
if (config.baseURL === API_URL && !config.headers.Authorization) {
const token = store.getState().auth.access_token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
console.log(config);
}
}
return config;
},
(error) => {
console.log(error);
store.dispatch(setAPIErrorMessage(error.message));
return Promise.reject(error);
}
);
return axiosInstance;
}
You don't need to set authorization header in interceptors.response, you only need this in request interceptor.
You could declare your error handling in a closure function (with the action dispatch) to avoid repeating yourself.
I would also suggest to avoid handling errors directly in axios instance. You could define async redux actions using https://github.com/reduxjs/redux-thunk, and handle network errors at redux level (using fetchBegin, fetchSuccess, fetchFailure actions pattern). Then axios setup and redux setup would not be coupled anymore, which will allow you to change these tools in the future.
I have this module (src/api/axios.js) that exports an instance of Axios with custom baseURL and a header. I set in the header the token I retrieve with authenticate.getToken():
import Axios from "axios";
import authenticate from "../classes/Authenticate";
const axios = Axios.create({
baseURL: "http://localhost:3333/api",
headers: { "x-auth-token": authenticate.getToken() },
});
axios.defaults.headers.post["Content-Type"] = "application/json";
axios.interceptors.request.use(request => {
console.log(request);
return request;
}, error => {
console.log(error);
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
console.log(response);
return response;
}, error => {
console.log(error);
return Promise.reject(error);
});
export default axios;
I import axios.js in another module (src/api/client.js) where I handle requests:
import axios from "../api/axios";
export default {
// User
login(email, password) {
return axios.post("/authenticate/", { email, password });
},
// Schedule
getSchedule() {
return axios.get("/schedule/");
}
}
THE PROBLEM
If I import axios.js ONLY in client.js, I get this error:
TypeError: Cannot read property 'getToken' of undefined
It seems that the instance of Authenticated is undefined.
THE FIX THAT I DON'T UNDERSTAND
However, if I import axios.js in App.js AND in client.js it works. Why? The import of axios.js I have in App.js is not being used.
You can check out the repo here:
https://github.com/sickdyd/booking-manager/tree/master/frontend
I wrote the axios helper function to handle the error and authentication. I need to redirect to custom error page with custom message when error occurred
I use $nuxt.error({message}) to do this function.
Helper
import axios from 'axios'
const myAxios = axios.create({
headers: { 'Accept': 'application/json' }
})
myAxios.interceptors.response.use((response) => {
return response
}, (error) => {
const { response } = error
const { status, statusText } = response
if (process.client) {
$nuxt.error({ message: statusText, statusCode: status })
} else {
console.log(this,$nuxt,$vm,app,context ....) // all undefined
}
return Promise.reject(error)
})
export default myAxios
Code
import myAxios from 'PATH/TO/THIS/HELPER'
..
...
..
myAxios.get('http://example.com')
It work perfectly. on client side only, when I refresh and run it on server side, it will return $nuxt is not defined
How to access nuxt in SSR?
I am trying to use a header token with axios. However I am presented with a CORS error as I am clearly not passing over the token correctly (moving to a not authorized feed works)
Here is my http-common.js file
const token = `08E1B4C220E671AC6A48`
// my user app token from micro.blog 08E1B4C220E671AC6A48
export const HTTP = axios.create({
// baseURL: 'https://micro.blog/feeds/adamprocter.json'
baseURL: 'https://micro.blog',
headers: {
Authorization: `Bearer ${token}`
}
})
and here is my Timeline.vue component
import { HTTP } from '#/http-common'
export default {
components: {
MicroPosts
},
data() {
return {
posts: []
}
},
created() {
// no auth get = HTTP.get('')
HTTP.get('/account/verify')
.then(response => {
//console.log(response.data)
this.posts = response.data.items
})
.catch(error => {
console.log('caught error' + error.response)
})
}
}
The URL is correct but the token is failing (I believe)
POST /account/verify — Accepts an app token (which I have set up) and returns an auth token and other details.
This is the API documentation which is a little sparse but
http://help.micro.blog/2017/api-json/
http://help.micro.blog/2018/api-authentication/
I am sure it is something obvious, any help much appreciated.
The documentation says /account/verify accepts POST. You are sending a GET.