You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Lambda NodeJS:Parameter Store取值后全局变量赋值异步问题

解决Node.js Lambda从AWS Parameter Store获取密码的异步问题

问题场景

开发NodeJS Lambda应用时,需要从AWS Parameter Store获取加密字符串作为基础访问认证的密码,但受Node.js异步特性影响,后续代码无法获取到正确的密码值:

  • 全局变量authPass初始值为default
  • 调用异步方法getParameterFromSystemManager后,立即执行后续代码时,authPass仍为初始值
  • 异步回调触发时才会更新authPass为正确值password2,但此时认证逻辑已经执行完毕

原代码

'use strict';
const AWS = require('aws-sdk');
const ssm = new AWS.SSM({region: 'us-east-1'});
var authPass = 'default';
let authUser = 'user';

exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    getParameterFromSystemManager( 
        (data) => {
            authPass = data;
            console.log('Inside func authPass : ', authPass); // 此处输出正确值password2
        }
    );
    
    console.log("Outside function call : ", authPass);  // 此处输出初始值default

    // Construct the Basic Auth string
    const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');
    
    
    // Require Basic authentication
    if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
            status: '401',
            statusDescription: 'Unauthorized',
            body: body,
            headers: {
                'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
            },
        };
        callback(null, response);
    }
    callback(null, request);
};


function getParameterFromSystemManager(callback) {
    var params = {
        Name: '/Path/ToPassword/EncryptedString',
        WithDecryption: true
    };
    ssm.getParameter(params, function(err, data) {
        if (err) {
            console.log(err, err.stack); // an error occurred
        } else {
            callback(data.Parameter.Value);
        }
    });
}

运行日志

Function Logs
START RequestId: 7d2eaccf-f064-4a5b-94c2-f8ff666dxxxx Version: $LATEST
2023-05-18T00:21:13.937Z    7d2eaccf-f064-4a5b-94c2-f8ff666dxxxx    INFO    Outside function call :  default
2023-05-18T00:21:14.177Z    7d2eaccf-f064-4a5b-94c2-f8ff666dxxxx    INFO    Inside func : data password2 authPass password2
END RequestId: 7d2eaccf-f064-4a5b-94c2-f8ff666dxxx
REPORT RequestId: 7d2eaccf-f064-4a5b-94c2-f8ff666dxxxx  Duration: 676.17 ms Billed Duration: 677 ms Memory Size: 128 MB Max Memory Used: 81 MB  Init Duration: 503.74 ms

问题原因

Node.js的异步非阻塞特性导致:getParameterFromSystemManager调用后,JavaScript会继续执行后续的console.log、认证逻辑等代码,而不会等待异步操作完成。只有当AWS SSM的API请求返回结果后,才会触发回调函数更新authPass,但此时认证逻辑已经执行完毕,使用的还是初始的default值。

解决方案

方案1:将认证逻辑移到异步回调内

把所有依赖authPass的代码放到回调函数中,确保只有获取到正确密码后才执行认证逻辑:

'use strict';
const AWS = require('aws-sdk');
const ssm = new AWS.SSM({region: 'us-east-1'});
let authUser = 'user';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    getParameterFromSystemManager( 
        (authPass) => {
            console.log('Inside func authPass : ', authPass);
            // 构造认证字符串
            const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');
            
            // 执行认证逻辑
            if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
                const body = 'Unauthorized';
                const response = {
                    status: '401',
                    statusDescription: 'Unauthorized',
                    body: body,
                    headers: {
                        'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
                    },
                };
                callback(null, response);
                return;
            }
            callback(null, request);
        },
        (err) => {
            // 处理获取参数失败的情况
            console.error('Failed to get parameter:', err);
            const response = {
                status: '500',
                statusDescription: 'Internal Server Error',
                body: 'Server Error',
            };
            callback(null, response);
        }
    );
};

function getParameterFromSystemManager(successCallback, errorCallback) {
    var params = {
        Name: '/Path/ToPassword/EncryptedString',
        WithDecryption: true
    };
    ssm.getParameter(params, function(err, data) {
        if (err) {
            errorCallback(err);
        } else {
            successCallback(data.Parameter.Value);
        }
    });
}

方案2:使用Promise + Async/Await(推荐)

将异步方法封装为Promise,然后在Lambda handler中使用async/await语法,让代码逻辑更线性、易读:

'use strict';
const AWS = require('aws-sdk');
const ssm = new AWS.SSM({region: 'us-east-1'});
const authUser = 'user';

// 将getParameter封装为Promise
async function getParameterFromSystemManager() {
    const params = {
        Name: '/Path/ToPassword/EncryptedString',
        WithDecryption: true
    };
    try {
        const data = await ssm.getParameter(params).promise();
        return data.Parameter.Value;
    } catch (err) {
        console.error('Failed to get parameter:', err);
        throw err;
    }
}

// 使用async handler
exports.handler = async (event, context) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    try {
        // 等待获取密码完成
        const authPass = await getParameterFromSystemManager();
        console.log('Got authPass:', authPass);

        // 构造认证字符串
        const authString = 'Basic ' + Buffer.from(`${authUser}:${authPass}`).toString('base64');
        
        // 执行认证逻辑
        if (!headers.authorization || headers.authorization[0].value !== authString) {
            return {
                status: '401',
                statusDescription: 'Unauthorized',
                body: 'Unauthorized',
                headers: {
                    'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
                },
            };
        }
        return request;
    } catch (err) {
        return {
            status: '500',
            statusDescription: 'Internal Server Error',
            body: 'Server Error',
        };
    }
};

说明

  • 方案2使用了AWS SDK内置的.promise()方法将回调式API转换为Promise,配合async/await让异步代码看起来像同步代码,可读性更强
  • 两种方案都确保了认证逻辑在获取到正确密码后才执行,避免了异步时序问题
  • 新增了错误处理逻辑,当获取参数失败时返回500错误,提升了代码健壮性

内容的提问来源于stack exchange,提问作者Milind Rajpoot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:55:02