In fact, retrieve the file from an S3 bucket and save it to your local

I've been attempting to retrieve an s3 file from my bucket using this function:

async Export()
{
  const myKey = '...key...'
   const mySecret = '...secret...'
  AWS.config.update(
    {
      accessKeyId: myKey,
      secretAccessKey: mySecret
    }
  );

  var s3 = new AWS.S3();

  s3.getObject({
    Bucket: '...bucket...',
    Key: '...filepath...'
  },
  function(error, data)
  {
    if (error != null)
    {
      alert("Failed to retrieve object: " + error)
    }
    else {
      alert("Loaded " + data.ContentLength + " bytes")
    }
  })
 }

After running the function, I receive a message indicating that I have successfully loaded a file consisting of a certain number of bytes. However, my main objective is to download the file onto my local machine. Do I need to implement a file stream mechanism here?

Additional Information

We are utilizing Angular Typescript, not AngularJS

Answer №1

A smart way to handle file downloads is by retrieving a signed URL from S3 instead of directly saving it as a stream. This allows for more dynamic and secure downloading options. Check out the following code snippet for guidance:

const AWS = require('aws-sdk')
const s3 = new AWS.S3()
AWS.config.update({accessKeyId: 'your access key', secretAccessKey: 'you secret key'})

const myBucket = 'bucket-name'
const myKey = 'path/to/your/key/file.extension'
const signedUrlExpireSeconds = 60 * 5 // expiry time in seconds.

const url = s3.getSignedUrl('getObject', {
  Bucket: myBucket,
  Key: myKey,
  Expires: signedUrlExpireSeconds
})

Utilize this generated URL in your front-end to initiate the download action:

function download(url){
  $('<iframe>', { id:'idown', src:url }).hide().appendTo('body').click();
}
$("#downloadButton").click(function(){
  $.ajax({
    url: 'example.com/your_end_point',
    success: function(url){
      download(url);
    }
  })
});

Answer №2

After some investigation, I discovered that utilizing the backend is the most effective solution to this issue. I encountered a problem where I was trying to create an anchor tag that would download a file from an S3 URL upon clicking, but instead it would open the object in a new tab. The root of the problem turned out to be my Response Content Disposition. Here is how I resolved it by ensuring the file downloads directly to the filesystem:

Backend (I opted for Django and boto3):

    def get_file(self, obj):      
        client = boto3.client('s3', aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
                              aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY)

        return client.generate_presigned_url(
            'get_object',
            Params={
                'Bucket': settings.AWS_STORAGE_BUCKET_NAME,
                'Key': obj.key,
                'ResponseContentDisposition': 'attachment',
            },
            ExpiresIn=600)

Frontend (leveraging Angular):

<a [href]="what_i_returned_from_backend" [download]="answer.png" target="_self" rel="noopener noreferrer">Download</a>

Answer №3

In my Spring + Angular web application, there is a list of files available for download by users. When a user clicks on a file name, the UI sends a request to the API for a temporary download link, which is generated using AmazonS3.generatePresignedUrl().

  public String generateUrlByKey(String key) {
    log.debug("S3 - Get file OutputStream by key: {}", key);

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(new Date());
    calendar.add(Calendar.DATE, 1);
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(s3Properties.getBucket(),
                                                                          key,
                                                                          HttpMethod.GET);
    request.setExpiration(calendar.getTime());

    ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides();
    headerOverrides.setContentDisposition("attachment");
    request.withResponseHeaders(headerOverrides);

    return amazonS3.generatePresignedUrl(request).toString();
  }

It is important to note the line: headerOverrides.setContentDisposition("attachment"); This ensures that when a user clicks on a file link, the file is downloaded instead of opened in the browser.

I am dynamically clicking on file links after obtaining the link in the UI:

  this.fileService.getTempUrlByFileId($event.id).subscribe({
    next: (url) => {
      const link: HTMLAnchorElement = document.createElement("a");
      link.href = url;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  });

The implementation of getTempUrlByFileId method:

  getTempUrlByFileId(id: number): Observable<string> {
    const url = `${this.API}/${id}`
    // @ts-ignore
    return this.http.get<string>(url, { responseType: 'text' });
  }

Answer №4

When dealing with browser cache issues, an effective solution is to navigate to the Chrome Dev Tools network tab and select "disable cache". This action will usually resolve any download issues. However, if you attempt to refresh the page without disabling the cache, downloading may fail consistently due to a CORS error.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

transmit data from Node.js Express to Angular application

I am making a request to an OTP API from my Node.js application. The goal is to pass the response from the OTP API to my Angular app. Here is how the API service looks on Angular: sendOtp(params): Observable<any> { return this.apiService.post(&q ...

Guide to altering the characteristics of a button

Here is the code for a button within My Template: <div *ngFor="let detail of details" class = "col-sm-12"> <div class="pic col-sm-1"> <img height="60" width="60" [src]='detail.image'> </div> <div ...

Issues with manipulating state using TypeScript Discriminated Unions"Incompatibility with setState

Imagine having a unique type structure like the one shown below: export type IEntity = ({ entity: IReport setEntity: (report: IReport) => void } | { entity: ITest setEntity: (test: ITest) => void }); Both the entity and setEntity fun ...

ng2-idle server side rendering problem - Uncaught ReferenceError: document is undefined

Can ng2-idle be used for idle timeout/keepalive with pre-rendering in Angular 4? I followed this link for implementation: It works fine without server pre-rendering, but when I add rendering back to my index.html, I keep getting the following error: Exce ...

What is the solution to the strict mode issue in ANGULAR when it comes to declaring a variable without initializing it?

Hi everyone! I'm currently learning Angular and I've encountered an issue when trying to declare a new object type or a simple string variable. An error keeps appearing. this_is_variable:string; recipe : Recipe; The error messages are as follows ...

ViewContainerRef fails to render component on the DOM

@Component({ selector: 'my-cmp', template: ` <div #target></div> ` }) export class MyCmp { @ViewChild('target', {read: ViewContainerRef}) target : ViewContainerRef; render() { let component = createComponent(met ...

Determining the return type of a function by analyzing its argument(s)

I'm interested in defining a method within a class that will have its type based on the argument provided in the constructor. For example: class A { private model: any; constructor(model: any) { this.model = model; } getModel( ...

The generic type does not narrow correctly when using extends union

I'm working with the isResult function below: export function isResult< R extends CustomResult<string, Record<string, any>[]>, K extends R[typeof _type] >(result: R, type: K): result is Extract<R, { [_type]: K }> { ...

Verify if the property in every element of the array is not empty

How can you determine if all employees have a non-null value for the SSN property in the given object? Employees: { id: 0, name: "John", SSN: "1234" } { id: 1, name: "Mark", SSN: "1876" } { id: 2, name: "Sue&q ...

Issue encountered while executing jest tests - unable to read runtime.json file

I've written multiple unit tests, and they all seem to pass except for one specific spec file that is causing the following error: Test suite failed to run The configuration file /Users/dfaizulaev/Documents/projectname/config/runtime.json cannot be r ...

Using ngrx, only the Array inside the Object retrieved by the GET-response is required

My issue involves using ngrx and trying to receive an Array of type "ReceivingObject". However, the problem arises when the GET-response returns it as an Array inside an Object structure. { "receivingObject": [ { "type": "xxx", "value": ...

The TS2345 error is triggered when using the fs.readFile function with specified string and

Attempting to utilize the fs.readFile method in TypeScript, my code looks like this... import {readFile} from 'fs'; let str = await readFile('my.file', 'utf8'); This results in the following error message: TS2345: Argumen ...

Utilizing Angular 4's piping feature to manipulate data sourced from an API observable within

I am currently working on setting up a filter for my stories. After subscribing to the API call, I receive the data in the form of an array of objects. However, I am encountering an error while trying to apply filters. Here is a snippet of relevant inform ...

Angular date selection with a range of plus two days, factoring in the exclusion of weekends

I am currently using a mat date picker range with specific logic. The minimum date that a user can select on the calendar is set to + 2 days. For example, if today's date is July 20, 2022, the minimum selectable date would be July 22, 2022. However, ...

Challenges with npm installation in Angular Quickstart

I've been following the Angular getting started guide and encountered some issues. After cloning the repository, I attempted to run npm install, but I'm encountering errors: npm WARN package.json <a href="/cdn-cgi/l/email-protection" class=" ...

Can someone assist me with writing nested ngFor loops in Angular?

Struggling to implement nested ngFor loops in Angular where each question has 3 radio button answers. Need guidance on how to keep the selected answer for each question isolated. Current code snippet: <ng-container *ngFor="let daType of daTypes&qu ...

Exploring the versatility of Angular by creating various flex layouts with Angular Material cards

I'm struggling to implement the design shown below using cards and a flex layout in a responsive way. I've tried working on it using StackBlitz but haven't been able to get it right - the margin and layout get messed up on different screens. ...

Encountering trouble with Angular material library following upgrade to Angular 6

Upon attempting to compile the application, I encountered the following error: ERROR in src/app/app.module.ts(15,5): error TS2304: Cannot find name 'MatToolbarModule'. src/app/app.module.ts(16,5): error TS2304: Cannot find name 'MatSidenavM ...

Sending data with an Http POST request in Angular 2

I'm having difficulty with a POST request that I am trying to make: sendRequest() { var body = 'username=myusername&password=mypassword'; var headers = new Headers(); headers.append('Content-Type', 'applicat ...

Angular: Tailoring the Context Menu

Currently, I am utilizing a helpful tutorial to implement a custom context menu feature. The main issue I am facing is that when a user interacts with the list items, I want the correct index of each item to be displayed. However, at the moment, clicking o ...