Home > Mobile >  How can I initiate a download of an external Image (AWS Signed URL) on button press
How can I initiate a download of an external Image (AWS Signed URL) on button press

Time:10-19

I'm trying to download an image from an s3 Presigned URL on a button click (from the client-side Nextjs).

Here's the background:

I'm using Golang on the backend. Nextjs React framework on the front end.

I started by trying to make a fetch call to the backend (since my AWS creds are stored accessible only via the back end). The backend would then download the image, and a download stream of mime-type "image/tiff":

Backend Handler (batch is just system-specific):


// GetDownloadBatchFile handles GET requests to download the batch output file
func GetDownloadBatchFile(ctx *atreugo.RequestCtx) error {


    // Parse Batch ID
    batchIntfID := ctx.UserValue("batch_id")
    batchStrID, isStr := batchIntfID.(string)

    if !isStr {
        fmt.Println("User error. No batch ID provided")
    }

    batchIntID, err := strconv.Atoi(batchStrID)
    if err != nil {
        fmt.Println("User error. Invalid batch ID provided")
    }

    // Get Batch
    batch, err := models.GetBatchByID(batchIntID)
    if err != nil {
        fmt.Println("User Error. No batch associated with provided batch ID")
    }

    // Get Batch Setting
    batch.BatchSetting, err = models.GetBatchSettingByID(batch.BatchSettingID)
    if err != nil {
        fmt.Println("User Error. No batch setting associated with provided batch setting ID")
    }

    // Get signed url and download
    req, _ := util.AWSS3Svc.GetObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String(batch.BatchSetting.AWSBucket),
        Key:    aws.String(batch.OutputFileKey),
    })

    // Get and Download Presigned URL
    URL, err := req.Presign(time.Hour * 1)
    if err != nil {
        fmt.Println("Whoops, failed to generate signed s3 preview link.")
    }

    resp, err := http.Get(URL)
    if err != nil {
        fmt.Println("System Error. Unable to download image file.")
    }

    batchImage,  err := tiff.Decode(resp.Body)
    if err != nil {
        fmt.Println(err)
    }


    ctx.Response.Header.Add("Content-Disposition", "attachment; filename=logo")
    ctx.Response.Header.SetContentType("image/tiff")
    err = tiff.Encode(ctx.Response.BodyWriter(), batchImage, &tiff.Options{Compression: tiff.Uncompressed}, uint32(batch.BatchSetting.DPI))
    if err != nil {
        return ctx.TextResponse(`ENCODE ERROR: `   err.Error())
    }

    return nil
}

This would normally work great, but the problem is my file is almost 1 GB! It takes too long to download and then the response just times out.

I'm thinking I should just send the presigned URL to the front end and download from that, but I can't figure out how to download from the URL.

All ideas welcome here, and also any information about how to download a url on button press. Thanks!

CodePudding user response:

I can't figure out how to download from the URL

I'm unclear on how you're trying currently trying to do this in Next.js, so I'll answer generally.

I would use the Next/image component and feed the signed URL to its src prop once it is available in the response from your backend.

import Image from "next/image";
import { useState } from "react";

// If signedSrc is available, render the image
const MyComponent = () => {
 const [signedSrc, signedSrcUpdate] = useState(null);

 return (
  <>
   <button onClick={async () => {
    // fetch signed image url
    const response = await fetch('https://your-api/signedimageurlendpoint';
    signedSrcUpdate(response.data);
   }}
   {signedSrc &&
    <Image
      src={signedSrc}
    />
   }
  </>
 )
}

CodePudding user response:

I found a solution that worked for me. I created a function and used plain javascript to download from a readstream (I also got my file to be much smaller at only 90mb), and set the button to load during the request. It's a long wait, but it's manageable. Here's the link to how to download a readstream in js.

How to download a ReadableStream on the browser that has been returned from fetch

  • Related