Reputation: 388
I'm using the @aws-sdk/client-s3
and I'm trying to read an image from a private bucket in AWS s3.
In my NextJS code, I have an API that should fetch the image and ultimately set the src
tag of the <img>
in the browser to display it. However I am not able to get it working and i'm unsure of the data I'm receiving back.
Here's the code to retrieve the image:
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();
}
}
Its just a screenshot I took and i'm trying to download again. When I console.log
the data returned from the getObject function, It looks a like this:
Then on the frontend side, I have the following function that receives the data
const getImage = async (event) => {
console.log('GET IMAGE')
// console.log(event.target)
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
}
And sets the src of the image. But the image isnt showing. The console.log output of the above function is:
GET IMAGE Asset.jsx:18:16
ArrayBuffer { byteLength: 687198 }
Asset.jsx:21:16
data:image/png;base64,Iu+/vVBOR1xyXG5cdTAwMWFcblx1MDAwMFx1MDAwMFx1MDAwMFxySUhEUlx1MDAwMFx1MDAwMFx1MDAwMixcdTAwMDBcdTAwMDBcdTAwMDIrXGJcdTAwMDZcdTAwMDBcdTAwMDBcdTAwMDDvv71y77+9UVx1MDAwMFx1MDAwMFx1MDAwMFx1MDAwNHNCSVRcYlxiXGJcYnxcYmTvv71cdTAwMDBcdTAwMDBcdTAwMDBcdTAwMTl0RVh0U29mdHdhcmVcdTAwMDBnbm9tZS1zY3JlZW5zaG9077+9XHUwMDAz77+9Plx1MDAwMFx1MDAwMFx1MDAwMCp0RVh0Q3JlYXRpb24gVGltZVx1MDAwMFdlZCAwOSBGZWIgMjAyMiAwODoxMzoyOSBHTVRcdTAwMTFcYllcdTAwMDRcdTAwMDBcdTAwMDAgXHUwMDAwSURBVHjvv73UvduS77+9Ou+/vSzvv71cdTAwMDHvv71S77+92rXvv73vv71M27zvv73vv71/77+9WO+/vV4p77+9QO+/vVx1MDAwNyBA77+9XHUwMDBiVGbvv71l77+9XHUwMDBm77+9ZCnvv70gXHUwMDEw77+9e1x1MDAwNC7vv73vv73vv73PvzlcdTAwMDB477+977+9Ke+/ve+/vWFmMDNs77+9XHUwMDEz77+9XHLvv71i77+9d++/ve+/vVBKXHUwMDAxXHUwMDAwLMuCbduQc0ZKXHTvv73vv71cdTAwMTPvv73vv73vv73vv71cdTAwMWRAKVx1MDAwNTnvv71277+9fT/vv71PKe+/ve+/vWvvv71cdTAwMDBcdTAwMDAz77+977+9fu+/ve+/ve+/vVnvv73vv70677+9Ne+/ve+/ve+/vVxuM8OyLHg+77+9XHUwMDAw77+977+9M++/ve+/vSc+Pj7vv73vv71w77+9UXfvv71377+964qcM++/vX3vv73vv71cdT…
All those slashes and /ve+ don't look correct to me, but I am at a loss as to what I'm doing wrong. I've tried about 5 different methods from all over stack overflow and I'm not able to get this image to show up. Can anyone help please.
Upvotes: 3
Views: 2968
Reputation: 46
All you have to change is:
...
// 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 data.Body.transformToString('base64');
...
Upvotes: 0
Reputation: 458
I think your problem is here:
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
and here
let base64 = 'data:image/png;base64,' + Buffer.from(arrayBuffer.data).toString('base64')
You are converting the response string to UTF and then converting to base64 here. Change the AWS stream to base64 like this:
stream.on("end", () => resolve(Buffer.concat(chunks).toString("base64")));
and remove the decode when you use the image here:
let base64 = 'data:image/png;base64,' + arrayBuffer.data;
Upvotes: 3