3

I am trying to make an onClick button to download a file from S3 bucket using pre-signet url. The problem comes when I received my url. I want an automatic redirect or kind of. In other words, how can I lunch the download file after getting back my signed url?

this is my document list

The onClick event is on the Download button.

redux action

Redux action call my nodejs route api route nodejs

Ask for pre-signed url then send it to my redux reducer.

Now in my front-end page, I got my link but I want an automatic redirect to start the file download. Part of Component

Hope my first post isn't too messy.

4 Answers4

5

I resolved my problem with a redux action. With one click I call my action, who return my pre-signed URL, then automatically click the link. This trigger download event with the original file name when I upload it to S3.

export const downDoc = (docId) => async dispatch => {
    
    const res = await axios({ url: 'myApiCall', method: 'GET', responseType: 'blob' })
    .then((response) => {
      console.log(response)
      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', `${docId.originalName}`);
      document.body.appendChild(link);
      link.click();
    });
0

The other answer does direct DOM manipulation, creates a blob, which looks as though it buffers the whole file in memory before sending it to the user and also creates a new link each time you download. A react-y of doing is:

const downloadFileRef = useRef<HTMLAnchorElement | null>(null);
const [downloadFileUrl, setDownloadFileUrl] = useState<string>();
const [downloadFileName, setDownloadFileName] = useState<string>();

const onLinkClick = (filename: string) => {
    axios.get("/presigned-url")
      .then((response: { url: string }) => {
        setDownloadFileUrl(response.url);
        setDownloadFileName(filename);
        downloadFileRef.current?.click();
      })
      .catch((err) => {
        console.log(err);
      });
  };

return (
<>
   <a onClick={() => onLinkClick("document.pdf")} aria-label="Download link">
       Download
   </a>
   <a
        href={downloadFileUrl}
        download={downloadFileName}
        className="hidden"
        ref={downloadFileRef}
   />
</>)

See here for more info https://levelup.gitconnected.com/react-custom-hook-typescript-to-download-a-file-through-api-b766046db18a

0

The way I did it was different and has the advantage of being able to see the progress of the download as the file is being downloaded. If you're downloading a large file then it makes a difference UX wise as you see feedback immediately.

What I did was:

  1. When creating the S3 presigned URL I set the content-disposition to `attachment
  2. I used an anchor element to download the actual item <a url='https://presigned-url' download>Download me</a>
n00b
  • 5,843
  • 11
  • 52
  • 82
0

Others have mentioned simulating a click within the DOM or React, but another option is to use window.open(). You can set the target attribute to _blank to open a tab, but you do need window.open() inside the click event to prevent popup blockers from stopping the functionality. There's some good discussion on the subject here. I found this to be a better solution than simulating a click event.

Here's an example (though there may be more needed depending on how you fetch the signed_url).

function downloadDocument() {
  const signedurlPromise = fetch("/signed_url")
  signedurlPromise.then((response) => {
      window.open(response.signed_url, "_blank");
  })
}
meadosc
  • 13
  • 1
  • 4