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

使用AWS GetObject从私有S3桶获取图片并在浏览器展示失败求助

问题:从S3私有桶读取图片并在Next.js中展示失败

使用@aws-sdk/client-s3工具从AWS S3私有存储桶读取图片,通过Next.js API接口获取后,无法在浏览器<img>标签中正常展示,生成的Base64内容包含大量异常字符,无法解析。

后端API代码(原错误版本)

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";

export const getObject = async () => {
    const s3Client = new S3Client({
        region: process.env.AWS_REGION,
        credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY,
            secretAccessKey: process.env.AWS_SECRET_KEY,
        },
    })
    console.log('GET OBJECT FUNC')
    try {
        // Create a helper function to convert a ReadableStream to a string.
        const streamToString = (stream) =>
            new Promise((resolve, reject) => {
                const chunks = [];
                stream.on("data", (chunk) => chunks.push(chunk));
                stream.on("error", reject);
                stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
            });

        // Get the object from the Amazon S3 bucket. It is returned as a ReadableStream.
        const data = await s3Client.send(new GetObjectCommand({
            Bucket: process.env.AWS_BUCKET,
            Delimiter: "/",
            Key: process.env.AWS_BUCKET_FOLDER + 'Screenshot from 2022-02-09 08-13-26.png'
        }));
        // return data; // For unit tests.
        // Convert the ReadableStream to a string.
        const bodyContents = await streamToString(data.Body);
        return bodyContents;
    } catch (err) {
        console.log("Error", err);
    }
};

export default async function handler(request, response) {
    if (request.method === "GET") {
        const data = await getObject()
        return response.status(200).json(data);
    } else {
        return response.status(405).end();
    }
}

前端请求代码(原错误版本)

const getImage = async (event) => {
    console.log('GET IMAGE')
    let arrayBuffer = await axios.get("/api/get-object", {responseType: 'arraybuffer'})
    console.log(arrayBuffer.data)
    let base64 = 'data:image/png;base64,' + Buffer.from(arrayBuffer.data).toString('base64')
    console.log(base64)
    event.target.src = base64
}

问题现象

后端将图片二进制流转成UTF-8字符串后返回,前端接收后转Base64时出现大量异常字符(如/ve+、转义斜杠等),导致<img>无法识别并展示图片。

解决方案

1. 修改后端API:直接返回二进制流

核心错误是将二进制图片转成UTF-8字符串,破坏了原始数据。修改后直接返回图片流并设置正确的Content-Type:

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { pipeline } from "stream/promises";

export const getObject = async () => {
    const s3Client = new S3Client({
        region: process.env.AWS_REGION,
        credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY,
            secretAccessKey: process.env.AWS_SECRET_KEY,
        },
    })
    try {
        const data = await s3Client.send(new GetObjectCommand({
            Bucket: process.env.AWS_BUCKET,
            Key: process.env.AWS_BUCKET_FOLDER + 'Screenshot from 2022-02-09 08-13-26.png'
        }));
        return data;
    } catch (err) {
        console.log("Error", err);
        throw err;
    }
};

export default async function handler(request, response) {
    if (request.method === "GET") {
        try {
            const data = await getObject();
            // 从S3返回的元数据中获取正确的Content-Type,没有则默认png
            response.setHeader('Content-Type', data.ContentType || 'image/png');
            // 将S3的可读流直接管道到响应流
            await pipeline(data.Body, response);
        } catch (err) {
            response.status(500).json({ error: err.message });
        }
    } else {
        response.status(405).end();
    }
}

2. 简化前端代码:直接使用API地址作为图片src

不需要转Base64,浏览器会自动处理二进制流:

const getImage = (event) => {
    event.target.src = "/api/get-object";
    // 可选:监听加载状态
    event.target.onload = () => console.log("图片加载成功");
    event.target.onerror = () => console.log("图片加载失败");
}

原理说明

图片是二进制文件,不能用UTF-8文本编码处理,否则会丢失或损坏原始字节。直接返回二进制流并设置正确的Content-Type后,浏览器可以直接识别并渲染图片,无需额外转码操作。

内容的提问来源于stack exchange,提问作者Richard Bridge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:45:11