Trying to stream s3 image to http response via lambda function URL

0

Hello,

I'm new to using AWS Lambda to stream HTTP responses. I am using typescript, node.js, and Lambda function URL and am building a Lambda application using SAM.

For a small image(less than 6MB), I was able to use "BUFFERED" invokeMode to return the image in the HTTP response. However, for an image bigger than 6MB, I wasn't able to do that as the maximum payload size is 6 MB for that invokeMode.

So, I am trying to stream an image in HTTP response using "STREAM_RESPONSE" invokeMode. I got to a point where the lambda function URL prompts download from the browser, and when I save the response, I can see the streamed image from s3. However, my goal is to stream the image from s3 and display it in the browser when I reach the lambda function URL. What should I do to achieve it? I think my issue is coming from the incorrect content type as the response content type is "application/octet-stream" even though I set my content type to "image/jpeg". Is there a way to prevent manually-set content-type in HTTP response from being overridden to application/octet-stream?

This is the output I see from POSTMAN when I send request to lambda function URL Enter image description here

Here's the code I used:

// lambda function
export const handler: Handler = awslambda.streamifyResponse(async (event, responseStream, context): Promise<any> => {
  let response: any;

  try {
    const s3Uri = `actual-s3-uri`;
    // Log the complete S3 URI
    logger.info({ s3Uri });
  
    // Parse the S3 URI to extract bucket and key
    const { bucket, key } = parseS3Uri(s3Uri);
    logger.info({bucket, key});
    
    const command = new GetObjectCommand({
      Bucket: bucket,
      Key: key,
    });
    const { Body: imageStream, ContentType: contentType, ContentLength } = await s3.send(command);

    if (!imageStream) {
      throw new Error('no body');
    }
    let srcStream;
    // Convert it to a Node.js readable stream
    if (imageStream instanceof Readable) {
        logger.info('imageStream is a readable stream');
        srcStream = imageStream;
    } else if (imageStream instanceof Blob) {
      logger.info('imageStream is a blob');
      const arrayBuffer = await imageStream.arrayBuffer();
      const blobStream = new Readable({
        read() {
          this.push(Buffer.from(arrayBuffer));
          this.push(null);
        }
      });
      srcStream = blobStream;
    } else {
      throw new Error('imageStream is neither a readable stream nor a blob');
    }
    
    logger.info({ contentType, ContentLength});

    // Return the processed image stream directly as the Lambda response
    response = {
      "statusCode": 200,
      "headers": {
        "Content-Type": "image/jpeg"
      },      
      "isBase64Encoded": false,
      "body": await pipeline(srcStream, responseStream), 
    };

    logger.info({statusCode: response.statusCode, headers: response.headers});
    
    return response;
  } catch (err: any) {
    logger.error({ err }, response);
    rollbar.error(err, response, { custom: {} });
    response = {
      statusCode: 500,
      body: JSON.stringify({ message: 'Unexpected error in lambda function' }),
    };
    throw err;
  } finally {
    await promiseRollbarWait(rollbar);
  }
});
Dahwi
asked a month ago445 views
1 Answer
0

I hope the URLs listed below will be of use to you.

It seems that you need to pass the header as metadata (JSON) to awslambda.HttpResponseStream.from in order to apply it.

https://repost.aws/ja/questions/QU9MFuTQKOR_WBo-klcQNa7Q/how-do-i-change-status-and-headers-when-streaming-with-lambda-and- function-url

https://github.com/astuyve/lambda-stream

profile picture
EXPERT
shibata
answered a month 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.

Guidelines for Answering Questions