Home > OS >  Why do I get a blank pdf when uploaded on S3?
Why do I get a blank pdf when uploaded on S3?

Time:10-08

I upload a pdf blob object to S3

      const params = {
        Bucket: "poster-print-bucket",
        Key: Date.now().toString()   ".pdf",
        Body: blob,
        contentType: "application/pdf",
      };

      const uploaded = await S3.upload(params).promise();

When I open a url which is i.e https://poster-print-bucket.s3.ca-central-1.amazonaws.com/1633526785678.pdf It downloads me a blank pdf

I thought maybe my blob is corrupted or something but I managed to upload same blob to firebase storage just fine.

btw I'm using nextjs api/upload-poster route

What's happening?

CodePudding user response:

I spent more time fixing this issue than I would like to admit. Here is the solution:

Frontend (converting blob to base64 before sending to backend):

            function toBase64(blob) {
              const reader = new FileReader();
              return new Promise((res, rej) => {
                reader.readAsDataURL(blob);
                reader.onload = function () {
                  res(reader.result);
                };
              });
            }

            toBase64(currentBlob)
              .then((blob) => {
                return axios
                  .post("/api/upload-poster", blob, {
                    headers: {
                      "Content-Type": "application/pdf",
                    },
                  })
                  .then(({ data }) => data.uploaded.Location);
              })

Backend:

      const base64 = req.body;
      const base64Data = Buffer.from(base64.replace(/^data:application\/\w ;base64,/, ""), "base64");
     
      const params = {
        Bucket: "poster-print-bucket",
        Key: nanoid()   ".pdf",
        Body: base64Data,
        ContentEncoding: "base64",
        contentType: "application/pdf",
      };

      const uploaded = await S3.upload(params).promise();

Why this all song and dance is required? Can it be something easier?

CodePudding user response:

Using the AWS SDK v3 (up-to-date at the time of this post), you could use PutObjectCommand which accepts a Uint8Array as Body params (docs).

Convert your Blob instance to an ArrayBuffer (docs), and your ArrayBuffer to an Uint8Array.

Code would look like:

const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const client = new S3Client(/* config */);

const arrayBuffer = await blob.arrayBuffer();
const typedArray = new Uint8Array(arrayBuffer);
await client.send(new PutObjectCommand({
   Bucket: /* ... */,
   Key: /* ... */,
   Body: typedArray,
}));

  • Related