abort all Axios requests when change route use vue-router - ajax

how can i abort / cancel Axios request before complete when i change route use
vue-router.
when user open page it automatically send axios request to get some data,
but user don't waiting to get response then he is changing route by vue-router
it will be a lot of Axios requests
so is there any solve to my problem

Update: Axios (0.22.0+)
CancelToken is now deprecated. Check #m0r answer for updated solution using AbortController. Here is the link from the official documentation:
https://axios-http.com/docs/cancellation
Original answer
Basically you have to generate a global cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
and use it in all your requests by passing it in the config parameter
GET request:
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
POST request:
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
Then, within a vue-router beforeEach navigation guard you can cancel all requests using:
source.cancel('Operation canceled by the user.');
Here's the official axios guide for cancellation: https://github.com/axios/axios#cancellation

Answer from #fabruex is correct. I just wanted to add here that if you have lot of api calls then you have to pass cancellation token in each api call config. In order to reduce that code, you can create axios instance and add request interceptor which will add that common cancellation token and then you can assign a new value to token when cancellation is done or your route has changed.
// Some global common cancel token source
let cancelSource = axios.CancelToken.source();
// Request interceptor
export const requestInterceptor = config => {
config.cancelToken = cancelSource.token;
return config;
};
// Add request interceptor like this
const request = axios.create({ baseURL: SOME_URL });
request.interceptors.request.use(requestInterceptor);
// Now you can use this axios instance like this
await request.get('/users');
// and
await request.post('/users', data);
// When you will cancel
cancelSource.cancel('Your cancellation message');
// And all the api calls initiated by axios instance which has request interceptor will be cancelled.
Edit to answer #Suneet Jain
You can create a class and create an instance which you can update
class CancelToken {
constructor(initialValue) {
this.source = initialValue;
}
getSource() {
return this.source;
}
setSource(value) {
this.source = value;
}
cancel() {
this.source.cancel();
}
}
export const cancelSource = new CancelToken(axios.CancelToken.source());
You can import that instance cancelSource and call cancel when required e.g. when you logout, you can call to cancel all request which have cancellation token given by cancelSource.getSource()
So after logout
cancelSource.cancel('CANCELLED');
And when again user will login, set new cancellation token to this global instance
cancelSource.setSource(axios.CancelToken.source());

2022 Update | Axios (0.22.0+)
CancelToken is deprecated. AbortController should be used now in new projects. The implementation is cleaner.
const controller = new AbortController();
Pass the controller in the config parameter:
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
And to cancel the request, simply use:
controller.abort()
source : https://github.com/axios/axios#cancellation

Related

Terminate a graphql request from Apollo Link

I have an ApolloLink setup for the AWSAppSyncClient in my React project to check if the user is authorized to make the graphql request. If the user is not authorized then, link should not invoke the forward method rather just return an Error for unauthorized access (making it a terminating link).
I tried returning the plain Error response (also tried it with Observable.of), but the request doesn't resolves but keeps on to retry the request on an endless loop.
Need a better solution to implement it.
const authLink = new ApolloLink((operation, forward) => {
const { operationName } = operation;
if (checkIfNotAuthorized(operationName)) {
const error = new Error('Access denied');
return { errors: [error], data: null };
}
return forward(operation);
});

How to handle auth token when doing SSR with next.js?

I want to find a way to inject user api_token on the server side.
When doing ssr, I come to a situation that I need to fetch data of authenticated user.
On client-side, "data fetching" is start with redux-thunk and handled by an axios client (a global instance with some basic config), and api_token is attached by "express" with 'http-proxy-middleware'.
On server-side, the axios client does not contain any auth related info. It seems that I need to initialize an axios client in each request cycle on server side and modify all my 'redux-thunk-data-fetching' actions to use axios client passed through 'redux-thunk-extra-args'.
I wonder if there is a better way to handle this situation.
Example:
// request is an axios instance with basic config.
// api_token is auto handle by proxy-middleware if the request is from client side.
const fetchUserInfo = (userId) => request(`/api/to/get/user-info/${userId}`);
// redux-thunk action
const asyncFetchUserInfo = (payload) => async (dispatch) => {
const data = await fetchUserInfo(payload.userId);
dispatch(loadUserInfo(data));
}
class UserPage extends React.Component {
render() {
return <div>Example Page</div>
}
}
UserPage.getInitialProps = async ({ store, req }) => {
const userInfo = await store.dispatch(asyncFetchUserInfo({ userId: req.userId }));
return { userInfo }
}
Project sturcture:
[ client ] --> [ express(nodejs) ] --> [ api-server ]
client
React + Redux + redux-thunk + axios
An express server
do SSR with next.js
manage cookie-session with Redis ( user api_token is stored in session)
handle api proxy from browser (add auth headers based on session info)

Nuxt Apollo with dynamic headers for a session based authentication

Apollo is not storing the header from the query dynamically.
pages/index.vue
methods: {
fetchCars() {
const token = Cookies.get('XSRF-TOKEN')
console.log(token) // 🟢 Token is shown in console
this.$apollo.query({
query: gql`
query {
cars {
uuid
name
}
}
`,
headers: {
'X-XSRF-TOKEN': token, // â­• Fetch without header
},
})
},
},
Is there a way to set the header value new for every Apollo request?
I have a separate Frontend and Backend. For the Frontend I am using Nuxt.js with Apollo. I want to have a session based communication with my server. For this reason I need to send the CSRF-Token with every Request.
Now the problem: On the first load of the page there is no Cookie set on the browser. I do a GET-Request on every initialization of my Nuxt application.
plugins/csrf.js
fetch('http://127.0.0.1:8000/api/csrf-cookie', {
credentials: 'include',
})
Now I have a valid Cookie set on my side and want to communicate with the GraphQL Server but my header is not set dynamically in the query. Does anyone know how I can solve this?
My Laravel Backend is throwing now a 419 Token Mismatch Exception because I did not send a CSRF-Token with my request.
Link to the repository: https://github.com/SuddenlyRust/session-based-auth
[SOLVED] Working solution: https://github.com/SuddenlyRust/session-based-auth/commit/de8fb9c18b00e58655f154f8d0c95a677d9b685b Thanks to the help of kofh in the Nuxt Apollo discord channel 🎉
In order to accomplish this, we need to access the code that gets run every time a fetch happens. This code lives inside your Apollo client's HttpLink. While the #nuxtjs/apollo module gives us many options, we can't quite configure this at such a high level.
Step 1: Creating a client plugin
As noted in the setup section of the Apollo module's docs, we can supply a path to a plugin that will define a clientConfig:
// nuxt.config.js
{
apollo: {
clientConfigs: {
default: '~/plugins/apollo-client.js'
}
}
}
This plugin should export a function which receives the nuxt context. It should return the configuration to be passed to the vue-cli-plugin-apollo's createApolloClient utility. You don't need to worry about that file, but it is how #nuxtjs/apollo creates the client internally.
Step 2: Creating the custom httpLink
In createApolloClient's options, we see we can disable defaultHttpLink and instead supply our own link. link needs to be the output of Apollo's official createHttpLink utility, docs for which can be found here. The option we're most interested in is the fetch option which as the docs state, is
a fetch compatible API for making a request
This boils down to meaning a function that takes uri and options parameters and returns a Promise that represents the network interaction.
Step 3: Creating the custom fetch method
As stated above, we need a function that takes uri and options and returns a promise. This function will be a simple passthrough to the standard fetch method (you may need to add isomorphic-fetch to your dependencies and import it here depending on your setup).
We'll extract your cookie the same as you did in your question, and then set it as a header. The fetch function should look like this:
(uri, options) => {
const token = Cookies.get('XSRF-TOKEN')
options.headers['X-XSRF-TOKEN'] = token
return fetch(uri, options)
}
Putting it all together
Ultimately, your ~/plugins/apollo-client.js file should look something like this:
import { createHttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-fetch'
export default function(context) {
return {
defaultHttpLink: false,
link: createHttpLink({
uri: '/graphql',
credentials: 'include',
fetch: (uri, options) => {
const token = Cookies.get('XSRF-TOKEN')
options.headers['X-XSRF-TOKEN'] = token
return fetch(uri, options)
}
})
}
}

redux test Actions must be plain objects. Use custom middleware for async actions

I am not using redux-thunk. this keeps error-ing and I am not sure how to fix it. The examples I see online use redux-thunk which I am not using
my repo is here and the file I am trying to test is in tests\actions\...
My action that is being called in the test
import axios from "axios";
var CancelToken = axios.CancelToken;
let fetch_cancel;
export const FETCH_CATEGORIES = "fetch_categories";
export async function fetchCategories() {
fetch_cancel && fetch_cancel();
const request = await axios.get(
`https://d1i9eedhsgvpdh.cloudfront.net/production-plentific-static/api-cache/find-a-pro/api/v1/categories/all.json`,
{
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
fetch_cancel = c;
})
}
);
return {
type: FETCH_CATEGORIES,
payload: request
};
}
The error message means that your actions must be plain objects. For example:
store.dispatch({
type: 'ADD_TODO',
text: 'Understand the middleware'
})
If you make an async request, you can't just return an object, because you need to wait for the request to finish. If you return too early, you return a Promise.
However, I cannot reproduce your error in your sandbox.

How to get logged in user in adonis js websocket controller

I am trying to get the current logged in user details in a websocket controller. I tried like this
constructor ({ socket, request , auth}) {
this.socket = socket
this.request = request
this.auth=auth
}
async onClose (data) {
const user = await this.auth.user
console.log(user) // it gives null
}
I get null. How can I get the user details?
Thank you.
Since you have assigned auth object to controller's auth variable, i assume you have added the middleware to the routes in the socket.js file. if you have done that already, you can try the following line
async onClose (data) {
//const user = await this.auth.user
const user = this.auth.user // this.auth.user will give you anything you want
const id = user.id
const name = user.name
console.log(user) // it will console the authenticated user details
}
Hope it will help.

Resources