最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

express - Preventing Multiple Concurrent Requests in Node.js with AsyncAwait and some sort of Lock - Stack Overflow

programmeradmin0浏览0评论

Improving Authentication Lock to Prevent Multiple Concurrent Requests

I have a Node.js server that acts as a reverse proxy to my partner APIs. My mobile app makes 3 concurrent requests to my Node server, which then forwards the requests to the appropriate partner API.

The partner API requires an access_token via an authentication request. The token expires every hour, so once it becomes invalid, my server needs to re-authenticate.

The issue is that when the token expires or is invalid or null, all 3 concurrent requests see the token as invalid and try to authenticate simultaneously. However I want to just re authenticate 1 time.

I want to ensure that: Only one authentication request is made. The other two requests wait for the first authentication request to complete and then proceed with the newly acquired token.

Right now when I hit this 3 times concurrently with my iOS app, all 3 requests authenticate. I want to implement a better lock to my authentication. any ideas?

// api.js

let access_token = null;
let tokenExpiration = null;
let refreshingToken = false;

function isAccessTokenValid() {
    return Date.now() < tokenExpiration;
}

async function authenticate() {
    if (refreshingToken) {
        console.log("Token refresh in progress, waiting...");
        while (refreshingToken) {
            // Wait 1s before checking again
            await new Promise((resolve) => setTimeout(resolve, 100));
        }
        return access_token;
    }
    refreshingToken = true;

    let token = null;
    try {
        token = getBearerToken();
    } catch(error) {
        console.log('token err' + error);
    } finally {
        refreshingToken = false;
    }
    
    const headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": `Basic ${token}`
      };

    let url = new URL('');

    let body = new URLSearchParams();
    body.append("grant_type", "client_credentials");

    try {
        let res = await axios.post(url.toString(), body, { headers });
        access_token = res.data.access_token;
        tokenExpiration = Date.now() + (res.data.expires_in * 1000);

        console.log('Finished setting token');
        return
    } catch(error) {
        throw error
    }
}

const energyUsage = async (req, res, next) => {
    // check if access_token != null
    if (access_token == null || !isAccessTokenValid()) {
        await authenticate();
    }

    // make request
    const url = new URL('');

    let params = new URLSearchParams();

    const headers = {
        "Authorization": `Bearer ${access_token}`
    }
    
    try {
        const apiResponse = await axios.get(decodeURIComponent(url.toString()), {headers});
        
        const data = handleResponse(apiResponse.data);

        res.status(apiResponse.status).json(data);
    
    } catch(error) { 
        return next(new ErrorHandler('error fetching data', 400));
    }
}

Improving Authentication Lock to Prevent Multiple Concurrent Requests

I have a Node.js server that acts as a reverse proxy to my partner APIs. My mobile app makes 3 concurrent requests to my Node server, which then forwards the requests to the appropriate partner API.

The partner API requires an access_token via an authentication request. The token expires every hour, so once it becomes invalid, my server needs to re-authenticate.

The issue is that when the token expires or is invalid or null, all 3 concurrent requests see the token as invalid and try to authenticate simultaneously. However I want to just re authenticate 1 time.

I want to ensure that: Only one authentication request is made. The other two requests wait for the first authentication request to complete and then proceed with the newly acquired token.

Right now when I hit this 3 times concurrently with my iOS app, all 3 requests authenticate. I want to implement a better lock to my authentication. any ideas?

// api.js

let access_token = null;
let tokenExpiration = null;
let refreshingToken = false;

function isAccessTokenValid() {
    return Date.now() < tokenExpiration;
}

async function authenticate() {
    if (refreshingToken) {
        console.log("Token refresh in progress, waiting...");
        while (refreshingToken) {
            // Wait 1s before checking again
            await new Promise((resolve) => setTimeout(resolve, 100));
        }
        return access_token;
    }
    refreshingToken = true;

    let token = null;
    try {
        token = getBearerToken();
    } catch(error) {
        console.log('token err' + error);
    } finally {
        refreshingToken = false;
    }
    
    const headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": `Basic ${token}`
      };

    let url = new URL('https://myapi.com/auth');

    let body = new URLSearchParams();
    body.append("grant_type", "client_credentials");

    try {
        let res = await axios.post(url.toString(), body, { headers });
        access_token = res.data.access_token;
        tokenExpiration = Date.now() + (res.data.expires_in * 1000);

        console.log('Finished setting token');
        return
    } catch(error) {
        throw error
    }
}

const energyUsage = async (req, res, next) => {
    // check if access_token != null
    if (access_token == null || !isAccessTokenValid()) {
        await authenticate();
    }

    // make request
    const url = new URL('https://myapi.com');

    let params = new URLSearchParams();

    const headers = {
        "Authorization": `Bearer ${access_token}`
    }
    
    try {
        const apiResponse = await axios.get(decodeURIComponent(url.toString()), {headers});
        
        const data = handleResponse(apiResponse.data);

        res.status(apiResponse.status).json(data);
    
    } catch(error) { 
        return next(new ErrorHandler('error fetching data', 400));
    }
}
Share Improve this question asked Feb 5 at 18:41 Trey6Trey6 3224 silver badges17 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

You can use this workaround.

let access_token = null;
let tokenExpiration = null;
let refreshingToken = false;
let isProcessing = null; // New global check

const energyUsage = async (req, res, next) => {
    // check if access_token != null
    if ((access_token == null || !isAccessTokenValid()) && !isProcessing ) {
        isProcessing = authenticate();
    }

    await isisProcessing; // This will await next request until it's fulfilled 

    // make request
    const url = new URL('https://myapi.com');

    let params = new URLSearchParams();

    const headers = {
        "Authorization": `Bearer ${access_token}`
    }
    
    try {
        const apiResponse = await axios.get(decodeURIComponent(url.toString()), {headers});
        
        const data = handleResponse(apiResponse.data);

        res.status(apiResponse.status).json(data);
    
    } catch(error) { 
        return next(new ErrorHandler('error fetching data', 400));
    }
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论