浏览器端AWS SDK访问Wasabi S3时SharedIniFileCredentials报错解决
问题根因
SharedIniFileCredentials是AWS SDK为Node.js服务端环境设计的专属凭证类,依赖Node.js原生fs文件系统模块读取本地~/.aws/credentials配置文件,浏览器环境无本地文件系统访问权限,webpack打包前端资源时会直接剔除该Node专属模块,因此会抛出「is not a constructor」错误。
除此之外你的实现存在致命安全风险:禁止在前端浏览器代码中写入S3/ Wasabi永久访问密钥,前端代码对用户完全公开,任何人打开开发者工具就能拿到密钥,可随意操作存储桶资源、产生高额账单。
推荐解决方案(无安全风险,适配Next.js特性)
不要在前端直接调用S3 SDK,借助Next.js的服务端能力做资源代理,S3交互逻辑全部放在服务端执行,密钥全程不暴露给前端,你原有Node.js环境下的S3逻辑几乎可以直接复用。
- 新建Next.js服务端接口处理Wasabi资源请求
如果使用Pages Router,在pages/api目录下新建接口文件:
// pages/api/wasabi-asset/[...key].js import AWS from 'aws-sdk'; // 该段代码仅在服务端运行,环境变量不会打包进前端代码 const s3 = new AWS.S3({ accessKeyId: process.env.NX_WASABI_KEY, secretAccessKey: process.env.NX_WASABI_SECRET, region: process.env.NX_WASABI_REGION, endpoint: new AWS.Endpoint(process.env.NX_WASABI_ENDPOINT), s3ForcePathStyle: true }); export default async function handler(req, res) { // 拼接文件key,支持多级路径 const fileKey = Array.isArray(req.query.key) ? req.query.key.join('/') : req.query.key; try { const objectData = await s3.getObject({ Bucket: process.env.NX_WASABI_BUCKET, Key: fileKey }).promise(); // 设置正确的资源类型与缓存头 res.setHeader('Content-Type', objectData.ContentType || 'image/jpeg'); res.setHeader('Cache-Control', 'public, max-age=86400'); res.send(objectData.Body); } catch (err) { res.status(404).send('资源不存在'); } }
如果使用App Router,可在app/api目录下新建对应的Route Handler,逻辑完全一致。
- 简化前端组件代码
不需要手动拉取Buffer转base64,直接将图片地址指向你自建的服务端接口即可,性能更好、代码更简洁:
import Image from 'next/image'; import styles from './PaletteImage.module.scss'; interface Props { name: string; source: string; } const PaletteImage = ({ name, source }: Props) => { return ( <div className={styles.imageContainer}> <Image alt={name} layout="fill" objectFit="contain" objectPosition="left top" src={`/api/wasabi-asset/${encodeURIComponent(source)}`} /> </div> ); }; export default PaletteImage;
不推荐方案(仅特殊场景使用)
如果因业务需求必须在前端直连Wasabi,必须满足以下前提:
- 完全删除
SharedIniFileCredentials相关代码,该类无法在浏览器环境运行 - 禁止使用永久访问密钥,必须通过服务端调用STS生成有效期不超过15分钟的临时凭证,且临时凭证仅绑定对应资源的只读权限
- 前端初始化S3客户端时直接传入临时凭证:
import AWS from 'aws-sdk'; // 注意:前端可读取的环境变量需要按框架要求添加公共前缀(Next.js为NEXT_PUBLIC_,NX为NX_PUBLIC_) const s3 = new AWS.S3({ accessKeyId: 临时凭证.accessKeyId, secretAccessKey: 临时凭证.secretAccessKey, sessionToken: 临时凭证.sessionToken, // 临时凭证必须传该参数 region: process.env.NEXT_PUBLIC_WASABI_REGION, endpoint: process.env.NEXT_PUBLIC_WASABI_ENDPOINT, s3ForcePathStyle: true, signatureVersion: 'v4' });
补充说明:你原有Node.js代码中先实例化SharedIniFileCredentials再手动赋值密钥的写法完全冗余,Node.js环境下也可以直接将密钥传入S3构造函数,不需要依赖本地ini配置文件。
内容的提问来源于stack exchange,提问作者Miha Šušteršič
相关产品推荐
相关产品推荐

