Jak pobrać plik za pomocą Angular2

Mam aplikację WebApi / MVC, dla której rozwijam klienta angular2 (aby zastąpić MVC). Mam pewne problemy ze zrozumieniem, jak Angular zapisuje plik.

Żądanie jest w porządku (działa dobrze z MVC i możemy rejestrować otrzymane dane), ale nie mogę dowiedzieć się, jak zapisać pobrane dane (głównie postępuję zgodnie z tą samą logiką jak w Ten post). Jestem pewien, że jest to głupio proste, ale jak na razie po prostu tego nie chwytam.

Kod funkcji składowej jest poniżej. Próbowałem różnych alternatyw, sposób blob powinien być sposobem, aby przejść tak daleko, jak rozumiem, ale nie ma funkcji createObjectURL w URL. Nie mogę nawet znaleźć definicji URL w oknie, ale najwyraźniej istnieje. Jeśli użyję FileSaver.js Moduł dostaję ten sam błąd. Więc myślę, że jest to coś, co zmieniło się niedawno lub nie jest jeszcze zaimplementowane. Jak mogę uruchomić zapis pliku w formacie A2?

downloadfile(type: string){

    let thefile = {};
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(data => thefile = new Blob([data], { type: "application/octet-stream" }), //console.log(data),
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    let url = window.URL.createObjectURL(thefile);
    window.open(url);
}

Ze względu na kompletność, usługa pobierająca dane jest poniżej, ale jedyne, co robi, to wydać żądanie i przekazać dane bez mapowania, jeśli się powiedzie:

downloadfile(runname: string, type: string){
   return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .catch(this.logAndPassOn);
}

Uwaga: wiem, że nie jest to minimalny przykład pracy, ale włożyłem wiele wysiłku w opis problemu. Jeśli masz zamiar przegłosować proszę zostaw komentarz, jak również.

Author: Frederik Struck-Schøning, 2016-02-01

18 answers

Problem polega na tym, że obserwowalny uruchamia się w innym kontekście, więc kiedy próbujesz utworzyć var adresu URL, masz pusty obiekt, a nie obiekt blob, który chcesz.

Jeden z wielu sposobów, które istnieją, aby rozwiązać ten problem, jest następujący:

this._reportService.getReport().subscribe(data => this.downloadFile(data)),//console.log(data),
                 error => console.log("Error downloading the file."),
                 () => console.info("OK");

Gdy żądanie jest gotowe, wywoła funkcję "downloadFile", która jest zdefiniowana w następujący sposób:

downloadFile(data: Response){
  var blob = new Blob([data], { type: 'text/csv' });
  var url= window.URL.createObjectURL(blob);
  window.open(url);
}

Blob został stworzony idealnie, więc adres URL var, jeśli nie otwiera nowego okna, sprawdź, czy już zaimportowałeś "rxjs/Rx";

  import 'rxjs/Rx' ;
Mam nadzieję, że to ci pomoże.
 94
Author: Alejandro Corredor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:04:12

Spróbuj tego !

1-Zainstaluj zależności dla wyskakującego okienka Zapisz / Otwórz plik

npm install file-saver --save
npm install @types/file-saver --save

2-Utwórz usługę z tą funkcją, aby otrzymać DANE

downloadFile(id): Observable<Blob> {
    let options = new RequestOptions({responseType: ResponseContentType.Blob });
    return this.http.get(this._baseUrl + '/' + id, options)
        .map(res => res.blob())
        .catch(this.handleError)
}

3 - w komponencie analizuje obiekt blob za pomocą 'file-saver'

import {saveAs as importedSaveAs} from "file-saver";

  this.myService.downloadFile(this.id).subscribe(blob => {
            importedSaveAs(blob, this.fileName);
        }
    )
To mi pasuje!
 49
Author: Hector Cuevas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:05:11

Jeśli nie musisz dodawać nagłówków w żądaniu, aby pobrać plik w Angular2, możesz zrobić proste:

window.location.href='http://example.com/myuri/report?param=x';

W Twoim komponencie.

 14
Author: surfealokesea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 07:13:44

Pobierz *.zip rozwiązanie dla angular 2.4.x: musisz zaimportować ResponseContentType z '@ angular / http'i zmienić responseType na ResponseContentType.ArrayBuffer (domyślnie jest to ResponseContentType.Json)

getZip(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
 let headers = this.setHeaders({
      'Content-Type': 'application/zip',
      'Accept': 'application/zip'
    });

 return this.http.get(`${environment.apiUrl}${path}`, { 
   headers: headers, 
   search: params, 
   responseType: ResponseContentType.ArrayBuffer //magic
 })
          .catch(this.formatErrors)
          .map((res:Response) => res['_body']);
}
 13
Author: Alex Dzeiko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:07:01

Jak wspomniał Alejandro Corredor jest to prosty błąd zakresu. {[3] } jest uruchamiany asynchronicznie i open musi być umieszczony w tym kontekście, tak aby dane zostały załadowane po uruchomieniu pobierania.

Można to zrobić na dwa sposoby. Zgodnie z zaleceniami docs usługa zajmuje się pobieraniem i mapowaniem danych:
//On the service:
downloadfile(runname: string, type: string){
  var headers = new Headers();
  headers.append('responseType', 'arraybuffer');
  return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .map(res => new Blob([res],{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }))
            .catch(this.logAndPassOn);
}

Następnie, na komponencie po prostu SUBSKRYBUJEMY i zajmujemy się zmapowanymi danymi. Są dwie możliwości. pierwszy , jak sugerowano w oryginalnym poście, ale wymaga małej korekty, jak zauważył Alejandro: {]}

//On the component
downloadfile(type: string){
  this.pservice.downloadfile(this.rundata.name, type)
      .subscribe(data => window.open(window.URL.createObjectURL(data)),
                  error => console.log("Error downloading the file."),
                  () => console.log('Completed file download.'));
  }

Drugim sposobem byłoby użycie FileReader. Logika jest taka sama, ale możemy jawnie poczekać, aż FileReader załaduje dane, unikając zagnieżdżania i rozwiązując problem asynchroniczny.

//On the component using FileReader
downloadfile(type: string){
    var reader = new FileReader();
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(res => reader.readAsDataURL(res), 
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    reader.onloadend = function (e) {
        window.open(reader.result, 'Excel', 'width=20,height=10,toolbar=0,menubar=0,scrollbars=no');
  }
}

Uwaga: próbuję pobrać plik Excela i mimo że pobieranie jest uruchamiane (więc to odpowiada na pytanie), plik jest uszkodzony. Zobacz odpowiedź na to post dla unikanie uszkodzonego pliku.

 12
Author: rll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:09:24

To jest dla ludzi, którzy szukają jak to zrobić używając HttpClient i file-saver:

  1. Install file-saver

Npm install file-saver --save

Npm install @types / file-saver --save

Klasa usługi API:

export() {
    return this.http.get(this.download_endpoint, 
        {responseType: 'blob'});
}

Składnik:

import { saveAs } from 'file-saver';
exportPdf() {
    this.api_service.export().subscribe(data => saveAs(data, `pdf report.pdf`));
}
 8
Author: Justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 07:15:52

Pobieranie pliku przez ajax jest zawsze bolesnym procesem i moim zdaniem najlepiej jest pozwolić serwerowi i przeglądarce wykonywać tę pracę negocjacji typu treści.

Myślę, że najlepiej jest mieć

<a href="api/sample/download"></a> 
Żeby to zrobić. To nawet nie wymaga otwierania nowych okien i takich tam.

Kontroler MVC jak w Twojej próbce może być podobny do poniższego:

[HttpGet("[action]")]
public async Task<FileContentResult> DownloadFile()
{
    // ...
    return File(dataStream.ToArray(), "text/plain", "myblob.txt");
}
 7
Author: Bharat Raj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-03 01:24:58

Co ty na to?

this.http.get(targetUrl,{responseType:ResponseContentType.Blob})
        .catch((err)=>{return [do yourself]})
        .subscribe((res:Response)=>{
          var a = document.createElement("a");
          a.href = URL.createObjectURL(res.blob());
          a.download = fileName;
          // start download
          a.click();
        })
Przydałoby mi się.
nie ma potrzeby dodatkowego pakietu.
 6
Author: harufumi.abe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:06:53

Aby pobrać i pokazać pliki PDF , bardzo podobny kod jest jak poniżej:

  private downloadFile(data: Response): void {
    let blob = new Blob([data.blob()], { type: "application/pdf" });
    let url = window.URL.createObjectURL(blob);
    window.open(url);
  }

  public showFile(fileEndpointPath: string): void {
    let reqOpt: RequestOptions = this.getAcmOptions();  //  getAcmOptions is our helper method. Change this line according to request headers you need.
    reqOpt.responseType = ResponseContentType.Blob;
    this.http
      .get(fileEndpointPath, reqOpt)
      .subscribe(
        data => this.downloadFile(data),
        error => alert("Error downloading file!"),
        () => console.log("OK!")
      );
  }
 3
Author: Baatar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:05:19

Dla osób stosujących wzór Redux

Dodałem do wygaszacza plików jako @Hector Cuevas nazwany w swojej odpowiedzi. Używając Angular2 V. 2. 3. 1, nie musiałem dodawać do @ types / file-saver.

Poniższym przykładem jest pobranie czasopisma w formacie PDF.

Działania dziennika

public static DOWNLOAD_JOURNALS = '[Journals] Download as PDF';
public downloadJournals(referenceId: string): Action {
 return {
   type: JournalActions.DOWNLOAD_JOURNALS,
   payload: { referenceId: referenceId }
 };
}

public static DOWNLOAD_JOURNALS_SUCCESS = '[Journals] Download as PDF Success';
public downloadJournalsSuccess(blob: Blob): Action {
 return {
   type: JournalActions.DOWNLOAD_JOURNALS_SUCCESS,
   payload: { blob: blob }
 };
}

The journal effects

@Effect() download$ = this.actions$
    .ofType(JournalActions.DOWNLOAD_JOURNALS)
    .switchMap(({payload}) =>
        this._journalApiService.downloadJournal(payload.referenceId)
        .map((blob) => this._actions.downloadJournalsSuccess(blob))
        .catch((err) => handleError(err, this._actions.downloadJournalsFail(err)))
    );

@Effect() downloadJournalSuccess$ = this.actions$
    .ofType(JournalActions.DOWNLOAD_JOURNALS_SUCCESS)
    .map(({payload}) => saveBlobAs(payload.blob, 'journal.pdf'))

Serwis dziennika

public downloadJournal(referenceId: string): Observable<any> {
    const url = `${this._config.momentumApi}/api/journals/${referenceId}/download`;
    return this._http.getBlob(url);
}

Serwis HTTP

public getBlob = (url: string): Observable<any> => {
    return this.request({
        method: RequestMethod.Get,
        url: url,
        responseType: ResponseContentType.Blob
    });
};

Dziennik reduktor chociaż ustawia to tylko poprawne Stany używane w naszej aplikacji, nadal chciałem go dodać, aby pokazać pełny wzór.

case JournalActions.DOWNLOAD_JOURNALS: {
  return Object.assign({}, state, <IJournalState>{ downloading: true, hasValidationErrors: false, errors: [] });
}

case JournalActions.DOWNLOAD_JOURNALS_SUCCESS: {
  return Object.assign({}, state, <IJournalState>{ downloading: false, hasValidationErrors: false, errors: [] });
}
Mam nadzieję, że to pomoże.
 3
Author: Casper Nybroe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:05:40

Podzielam rozwiązanie, które mi pomogło (każda poprawa jest bardzo mile widziana)

W serwisie 'pservice':

getMyFileFromBackend(typeName: string): Observable<any>{
    let param = new URLSearchParams();
    param.set('type', typeName);
    // setting 'responseType: 2' tells angular that you are loading an arraybuffer
    return this.http.get(http://MYSITE/API/FILEIMPORT, {search: params, responseType: 2})
            .map(res => res.text())
            .catch((error:any) => Observable.throw(error || 'Server error'));
}

Składnik Część:

downloadfile(type: string){
   this.pservice.getMyFileFromBackend(typename).subscribe(
                    res => this.extractData(res),
                    (error:any) => Observable.throw(error || 'Server error')
                );
}

extractData(res: string){
    // transforme response to blob
    let myBlob: Blob = new Blob([res], {type: 'application/vnd.oasis.opendocument.spreadsheet'}); // replace the type by whatever type is your response

    var fileURL = URL.createObjectURL(myBlob);
    // Cross your fingers at this point and pray whatever you're used to pray
    window.open(fileURL);
}

W części składowej dzwonisz do usługi bez subskrybowania odpowiedzi. The subscribe pełna lista typów mime openOffice znajduje się w: http://www.openoffice.org/framework/documentation/mimetypes/mimetypes.html

 3
Author: Ismail H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:10:12

Dla nowszych wersji kątowych:

npm install file-saver --save
npm install @types/file-saver --save


import {saveAs} from 'file-saver/FileSaver';

this.http.get('endpoint/', {responseType: "blob", headers: {'Accept': 'application/pdf'}})
  .subscribe(blob => {
    saveAs(blob, 'download.pdf');
  });
 3
Author: Tobias Ernst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 15:33:47

Używam Angular 4 z obiektem 4.3 httpClient. Zmodyfikowałem odpowiedź, którą znalazłem na blogu technicznym Js, który tworzy obiekt linku, używa go do pobierania, a następnie go niszczy.

Klient:

doDownload(id: number, contentType: string) {
    return this.http
        .get(this.downloadUrl + id.toString(), { headers: new HttpHeaders().append('Content-Type', contentType), responseType: 'blob', observe: 'body' })
}

downloadFile(id: number, contentType: string, filename:string)  {

    return this.doDownload(id, contentType).subscribe(  
        res => { 
            var url = window.URL.createObjectURL(res);
            var a = document.createElement('a');
            document.body.appendChild(a);
            a.setAttribute('style', 'display: none');
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove(); // remove the element
        }, error => {
            console.log('download error:', JSON.stringify(error));
        }, () => {
            console.log('Completed file download.')
        }); 

} 

Wartość tego.downloadUrl został wcześniej ustawiony tak, aby wskazywał na api. Używam tego do pobierania załączników, więc znam identyfikator, typ treści i nazwę pliku: Używam API MVC, aby zwrócić plik:

 [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public FileContentResult GetAttachment(Int32 attachmentID)
    { 
        Attachment AT = filerep.GetAttachment(attachmentID);            
        if (AT != null)
        {
            return new FileContentResult(AT.FileBytes, AT.ContentType);  
        }
        else
        { 
            return null;
        } 
    } 

Klasa attachment wygląda jak to:

 public class Attachment
{  
    public Int32 AttachmentID { get; set; }
    public string FileName { get; set; }
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; } 
}

Repozytorium filerep zwraca Plik z bazy danych.

Mam nadzieję, że to komuś pomoże:)

 2
Author: davaus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 07:17:11

Witam mam rozwiązanie do pobierania z angular 2 bez uszkodzenia .... użycie spring mvc i angular 2

1st-mój typ powrotu to: - response from java end....tutaj wysyłam bajt [] tablica ma typ zwracany z kontrolera.

2nd-aby umieścić plik w obszarze roboczym-na stronie indeksu jako: -

<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>

3rd-at component ts napisz ten kod: -

      import {ResponseContentType} from '@angular.core';

let headers = new Headers({ 'Content-Type': 'application/json', 'MyApp-Application' : 'AppName', 'Accept': 'application/pdf' });
        let options = new RequestOptions({ headers: headers, responseType: ResponseContentType.Blob });
            this.http
            .post('/project/test/export',
                    somevalue,options)
              .subscribe(data => {

                  var mediaType = 'application/vnd.ms-excel';
                  let blob: Blob = data.blob();
                    window['saveAs'](blob, 'sample.xls');

                });

To da ci format pliku xls...jeśli chcesz inne formaty Zmień mediatype i nazwa pliku z rozszerzeniem prawym...dziękuję, mam nadzieję, że to pomoże....

 1
Author: user2025069,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:06:43

Oto coś, co zrobiłem w moim przypadku -

// service method
downloadFiles(vendorName, fileName) {
    return this.http.get(this.appconstants.filesDownloadUrl, { params: { vendorName: vendorName, fileName: fileName }, responseType: 'arraybuffer' }).map((res: ArrayBuffer) => { return res; })
        .catch((error: any) => _throw('Server error: ' + error));
}

// a controller function which actually downloads the file
saveData(data, fileName) {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    let blob = new Blob([data], { type: "octet/stream" }),
        url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(url);
}

// a controller function to be called on requesting a download
downloadFiles() {
    this.service.downloadFiles(this.vendorName, this.fileName).subscribe(data => this.saveData(data, this.fileName), error => console.log("Error downloading the file."),
        () => console.info("OK"));
}

Rozwiązanie jest odwołane z - proszę.

 1
Author: Tushar Walzade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-01 10:07:20
 let headers = new Headers({
                'Content-Type': 'application/json',
                'MyApp-Application': 'AppName',
                'Accept': 'application/vnd.ms-excel'
            });
            let options = new RequestOptions({
                headers: headers,
                responseType: ResponseContentType.Blob
            });


this.http.post(this.urlName + '/services/exportNewUpc', localStorageValue, options)
                .subscribe(data => {
                    if (navigator.appVersion.toString().indexOf('.NET') > 0)
                    window.navigator.msSaveBlob(data.blob(), "Export_NewUPC-Items_" + this.selectedcategory + "_" + this.retailname +"_Report_"+this.myDate+".xlsx");

                    else {
                        var a = document.createElement("a");
                        a.href = URL.createObjectURL(data.blob());
                        a.download = "Export_NewUPC-Items_" + this.selectedcategory + "_" + this.retailname +"_Report_"+this.myDate+ ".xlsx";
                        a.click();
                    }
                    this.ui_loader = false;
                    this.selectedexport = 0;
                }, error => {
                    console.log(error.json());
                    this.ui_loader = false;
                    document.getElementById("exceptionerror").click();
                });
 0
Author: user2025069,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-19 17:20:23

Będzie lepiej, jeśli spróbujesz wywołać nową metodę wewnątrz siebie subscribe

this._reportService.getReport()
    .subscribe((data: any) => {
        this.downloadFile(data);
    },
        (error: any) => onsole.log(error),
        () => console.log('Complete')
    );

Wewnątrz downloadFile(data) funkcji musimy wykonać block, link, href and file name

downloadFile(data: any, type: number, name: string) {
    const blob = new Blob([data], {type: 'text/csv'});
    const dataURL = window.URL.createObjectURL(blob);

    // IE doesn't allow using a blob object directly as link href
    // instead it is necessary to use msSaveOrOpenBlob
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(blob);
      return;
    }

    const link = document.createElement('a');
    link.href = dataURL;
    link.download = 'export file.csv';
    link.click();

    setTimeout(() => {

      // For Firefox it is necessary to delay revoking the ObjectURL
      window.URL.revokeObjectURL(dataURL);
      }, 100);
    }
}
 0
Author: Volodymyr Khmil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 11:07:14

Zaktualizuj odpowiedź Hektora za pomocą wygaszacza plików i HttpClient dla kroku 2:

public downloadFile(file: File): Observable<Blob> {
    return this.http.get(file.fullPath, {responseType: 'blob'})
}
 0
Author: dmcgrandle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 20:50:56