Skip to content

I keep getting a broken image whenever an upload is sent to my S3 bucket using my Lambda function

0

I've built a chat app in React and I'm currently working on deploying the back-end API. My Lambda function, createAccount, is almost complete, but there's just one issue that needs to be addressed. My createAccount Lambda function, as you may have guessed by the name, is supposed to handle new users creating an account on the app by sending their information to my DynamoDB table, sending a welcome e-mail to their address, and uploading an image to my S3 bucket to use as their chosen profile picture. Here's the source code for the function's app.js file, and here's the React code for the account creation component.

The issue is, whenever an image is uploaded to my S3 bucket through this function, along with other user-submitted data using the multipart/formdata encoding type, I keep getting a broken image every time I open the public URL for the upload.

Enter image description here

I have all "Block public access" settings off for my bucket. I know that the correct file type (image/jpg) is being submitted, and my Lambda function has permission to access and perform operations on my S3 bucket. I also tried adding content types such as image/jpg and image/png to my API's binary media types to further ensure that my function was recognizing the image as binary data, so I'm not sure why the image is not accessible. Also, I've tried uploading the image by itself using a seperate Node.js/Express file containing the following code and it worked.

const express = require("express")
const aws = require("aws-sdk")
const cors = require("cors")
const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3")
const multer = require("multer")

const app = express()
const s3 = new S3Client({ region: "us-east-2" })

app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cors())

const storage = multer.memoryStorage()

const upload = multer({ 
  storage: storage
})

app.post("/upload", upload.single("profile_pic"), async function(req, res) {
  try {
    const uploadParams = {
      Bucket: "amplify-yappermsgapp-dev-5071b-deployment",
      Key: `user_uploads/${Date.now()}_${req.file.originalname}`,
      Body: req.file.buffer,
      ContentType: req.file.mimetype,
      ACL: "public-read"
    }

    const command = new PutObjectCommand(uploadParams)
    await s3.send(command)
    console.log("Upload successful!\n", req.file.mimetype)
    res.json({ 
      message: "Upload successful!",
      uploadUrl: `https://${uploadParams.Bucket}.s3.us-east-2.amazonaws.com/${uploadParams.Key}`
    })

  } catch (error) {
    console.log("Nothing has been uploaded\n", error)
  }
})

app.listen(5500, () => {
  console.log("Server running on port 5500")
})

The above code uploaded a perfectly working image that was accessible through its public URL, but the code in my Lambda function keeps uploading a broken image. Can anyone tell me what would be the problem?

2 Answers
1

The issue you're experiencing with broken images when uploading to S3 through your Lambda function is likely related to how the image data is being processed and sent to S3. There are a few potential causes and solutions to consider:

  1. Content-Type: Ensure that you're setting the correct Content-Type when uploading the file to S3. In your Lambda function, you should explicitly set the ContentType parameter when calling the S3 putObject method. This should match the MIME type of the uploaded image (e.g., 'image/jpeg' for JPEG files).

  2. File Buffer: Make sure you're passing the correct file buffer to S3. In Lambda, you might need to parse the multipart form data correctly to extract the file buffer. The 'busboy' library can be useful for parsing multipart form data in Node.js.

  3. Base64 Encoding: If the image data is being sent as a base64 encoded string, you need to decode it before uploading to S3. Use Buffer.from(base64String, 'base64') to convert it back to a buffer.

  4. File Corruption: Verify that the file isn't getting corrupted during the upload process. You can log the file size before and after processing to ensure it remains consistent.

  5. S3 Permissions: Double-check that your Lambda function has the correct permissions to write to the S3 bucket. The IAM role associated with your Lambda should have s3:PutObject permission for the target bucket.

  6. Error Handling: Implement proper error handling in your Lambda function to catch and log any issues during the upload process. This can help identify where the problem is occurring.

To resolve this, you could try modifying your Lambda function to more closely resemble the working Express.js code you provided. Ensure you're using the correct AWS SDK methods (like PutObjectCommand), setting the ContentType, and handling the file buffer properly.

If the issue persists, you may want to add logging throughout your Lambda function to track the file data at each step of the process. This will help pinpoint where the image data might be getting corrupted or mishandled.
Sources
Community | Secure File Uploads to S3 Using AWS Lambda
Serverless Image Handler

answered 2 years ago

EXPERT

reviewed 2 years ago

0
Accepted Answer

The problem has been solved. I just had to add "multipart/form-data" as a binary type to my API settings in the API Gateaway console. I guess this was required for my Lambda function to properly handle the data. I found the same solution on this thread.

Enter image description here

answered a year ago

EXPERT

reviewed a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.