Skip to content

Instantly share code, notes, and snippets.

@nzvtrk
Last active September 13, 2024 00:50
Show Gist options
  • Save nzvtrk/ebf494441e36200312faf82ce89de9f2 to your computer and use it in GitHub Desktop.
Save nzvtrk/ebf494441e36200312faf82ce89de9f2 to your computer and use it in GitHub Desktop.
Axios create/recreate cookie session in node.js enviroment
/* Basic example of saving cookie using axios in node.js and session's recreation after expiration.
* We have to getting/saving cookie manually because WithCredential axios param use XHR and doesn't work in node.js
* Also, this example supports parallel request and send only one create session request.
* */
const BASE_URL = "https://google.com";
// Init instance of axios which works with BASE_URL
const axiosInstance = axios.create({ baseURL: BASE_URL });
const createSession = async () => {
console.log("create session");
const authParams = {
username: "username",
password: "password"
};
const resp = await axios.post(BASE_URL, authParams);
const [cookie] = resp.headers["set-cookie"]; // getting cookie from request
axiosInstance.defaults.headers.Cookie = cookie; // attaching cookie to axiosInstance for future requests
return cookie; // return Promise<cookie> because func is async
};
let isGetActiveSessionRequest = false;
let requestQueue = [];
const callRequestsFromQueue = cookie => {
requestQueue.forEach(sub => sub(cookie));
};
const addRequestToQueue = sub => {
requestQueue.push(sub);
};
const clearQueue = () => {
requestQueue = [];
};
// registering axios interceptor which handle response's errors
axiosInstance.interceptors.response.use(null, error => {
console.error(error.message); //logging here
const { response = {}, config: sourceConfig } = error;
// checking if request failed cause Unauthorized
if (response.status === 401) {
// if this request is first we set isGetActiveSessionRequest flag to true and run createSession
if (!isGetActiveSessionRequest) {
isGetActiveSessionRequest = true;
createSession().then(cookie => {
// when createSession resolve with cookie value we run all request from queue with new cookie
isGetActiveSessionRequest = false;
callRequestsFromQueue(cookie);
clearQueue(); // and clean queue
}).catch(e => {
isGetActiveSessionRequest = false; // Very important!
console.error('Create session error %s', e.message);
clearQueue();
});
}
// and while isGetActiveSessionRequest equal true we create and return new promise
const retryRequest = new Promise(resolve => {
// we push new function to queue
addRequestToQueue(cookie => {
// function takes one param 'cookie'
console.log("Retry with new session context %s request to %s", sourceConfig.method, sourceConfig.url);
sourceConfig.headers.Cookie = cookie; // setting cookie to header
resolve(axios(sourceConfig)); // and resolve promise with axios request by old config with cookie
// we resolve exactly axios request - NOT axiosInstance's request because it could call recursion
});
});
return retryRequest;
} else {
// if error is not related with Unauthorized we just reject promise
return Promise.reject(error);
}
});
@Splines
Copy link

Splines commented May 11, 2021

We have to getting/saving cookie manually because WithCredential axios param use XHR and doesn't work in node.js

Good to know, that's why axios didn't work for me at all. axiosInstance.defaults.headers.Cookie = cookie; did the trick for me.


Just a question: I've never seen a variable declared and initialized like this in JS: const [cookie] = resp.headers["set-cookie"];. This is just saving the first cookie, right? I've removed the square brackets in [cookie] to deal with multiple cookies at once.

@nzvtrk
Copy link
Author

nzvtrk commented May 11, 2021

Just a question: I've never seen a variable declared and initialized like this in JS: const [cookie] = resp.headers["set-cookie"];. This is just saving the first cookie, right? I've removed the square brackets in [cookie] to deal with multiple cookies at once.

Sure, its about array destructuring in JavaScript. resp.headers["set-cookie"] returns array with one elem ['yourCookieHere'].
And we can use const [cookie] = resp.headers["set-cookie"]; instead of const cookie = resp.headers["set-cookie"][0];

Very nice work. Just a small thing:
line#64, it should be
console.log("Retry with new session context %s request to %s", sourceConfig.method, sourceConfig.url);
otherwise, it returns an error like "method undefined"

Thanks! fixed

@Splines
Copy link

Splines commented May 21, 2021

Sure, its about array destructuring in JavaScript. resp.headers["set-cookie"] returns array with one elem ['yourCookieHere'].
And we can use const [cookie] = resp.headers["set-cookie"]; instead of const cookie = resp.headers["set-cookie"][0];

@nzvtrk ah ok, thanks 👍

@Mengchen-He
Copy link

Have been stuck for 3h and your code works like a charm, thank you so much

@mscw
Copy link

mscw commented Jan 11, 2022

It works! Thank you so much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment