-
-
Save nzvtrk/ebf494441e36200312faf82ce89de9f2 to your computer and use it in GitHub Desktop.
/* 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); | |
} | |
}); |
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
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 👍
Have been stuck for 3h and your code works like a charm, thank you so much
It works! Thank you so much.
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.