ECS Fargate中使用AWS SDK for JavaScript读取Secrets Manager秘钥时出现Unexpected token ?语法错误
嘿,我来帮你拆解下这个问题!首先得明确:你遇到的Unexpected token ?错误和IAM权限、AWS认证完全没关系,核心问题出在容器里的Node.js版本太老,不支持AWS SDK v3用到的新语法特性。
问题根源
从CloudWatch日志的报错行能看到,AWS SDK的代码里用了??符号——这是ES2020引入的空值合并运算符,但你的容器运行的Node.js版本(看起来是v12或更早)并不支持这个语法,所以直接抛出了语法错误。AWS SDK for JavaScript v3官方要求Node.js版本至少是14.x,你的容器环境显然不满足这个最低要求。
解决方案
升级容器中的Node.js版本
打开你的Dockerfile,把基础镜像换成支持ES2020的Node.js LTS版本,比如18.x或者20.x。举个例子:# 原来的旧镜像(比如v12) # FROM node:12-alpine # 换成新的LTS镜像 FROM node:18-alpine重新构建镜像并部署到ECS Fargate,这个语法错误应该就能直接解决。
修复代码里的变量作用域问题
另外提醒你:你代码里的secret变量是在async立即执行函数里定义的,但fetch函数直接引用了这个变量,等Node.js版本升级后会出现secret is not defined的新错误。你需要调整变量作用域,比如把secret提升到模块级别:import getSearchQueryString from './query-string-builder'; import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager"; var BASE_PORT = "xxxx"; let secret; // 提升到模块作用域,让fetch函数能访问到 // 初始化秘钥的异步函数 (async function initSecret() { const secret_name = "secret"; const client = new SecretsManagerClient({}); try { const response = await client.send( new GetSecretValueCommand({ SecretId: secret_name, VersionStage: "AWSCURRENT", }) ); secret = response.SecretString; console.log("秘钥获取成功"); } catch (error) { console.error("秘钥获取失败:", error); throw error; } })(); // 调整fetch函数,确保秘钥初始化后再发起请求 function fetch(endpoint) { return new Promise((resolve) => { if (!secret) { const err = new Error("秘钥还未完成初始化"); console.error("fetch出错", err); resolve({ errors: true, error: err }); return; } const request = require('node-fetch'); console.log("访问地址:" + secret + ":" + BASE_PORT + endpoint); request(`${secret}:${BASE_PORT}${endpoint}`) .then(res => res.json()) .then(json => resolve(json)) .catch(err => { console.error("fetch请求失败", err); resolve({ errors: true, error: err }); }); }); } // 其余导出函数保持不变...关于IAM权限的补充确认
你之前对Fargate任务角色的配置是完全正确的——ECS Fargate会自动通过任务角色为容器提供AWS认证,根本不需要在代码里配置共享凭证文件。等Node.js版本升级和代码调整后,只要IAM角色拥有secretsmanager:GetSecretValue权限,就能正常读取秘钥了。
备注:内容来源于stack exchange,提问作者Dave Michaels

