Angular2 veya daha üstü bir dosyayı nasıl indirebilirim?


182

(MVC değiştirmek için) bir açısal2 istemci geliştiriyorum bir WebApi / MVC uygulaması var. Angular'ın bir dosyayı nasıl kaydettiğini anlama konusunda bazı sorunlar yaşıyorum.

İstek tamam (MVC ile iyi çalışıyor ve alınan verileri kaydedebiliriz) ama indirilen verileri nasıl kaydedeceğimizi anlayamıyorum (çoğunlukla bu yazıda olduğu gibi aynı mantığı takip ediyorum ). Eminim aptalca basit, ama şimdiye kadar basitçe kavramıyorum.

Bileşen işlevinin kodu aşağıdadır. Ben damla yolu bildiğim kadarıyla anlamış olarak gitmek için yol olmalıdır, farklı alternatifler denedim ama hiçbir işlevi yoktur createObjectURLiçinde URL. URLPencerenin tanımını bile bulamıyorum , ama görünüşe göre var. FileSaver.jsModülü kullanırsam aynı hatayı alıyorum. Bu yüzden sanırım bu son zamanlarda değişen veya henüz uygulanmayan bir şey. A2'de dosya kaydetmeyi nasıl tetikleyebilirim?

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);
}

Tamlık uğruna, verileri getiren hizmet aşağıdadır, ancak yaptığı tek şey isteği vermek ve başarılı olursa verileri eşlemeden iletmektir:

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

Bu yöntemle büyük dosyaları indiremezsiniz. Sekme başına bellek sınırına ulaşacaksınız. Bu 1-2GB kadar düşük olabilir.
Matthew B.

@MatthewB. daha iyi olanı söylemiş olsaydın.
steve

Büyük dosya indirmeleri için yeni bir sekme belirtmeniz gerekir; örneğin, bir <A> tıklamasını simüle ediyorsanız, hedefin "_blank" değerine eşit olması veya bir form göndermesi gerekir. Ajax tarzı isteklerle büyük dosya boyutu sınırlaması aşmanın temiz bir yolu olduğunu sanmıyorum.
Matthew B.

Yanıtlar:


181

Sorun gözlemlenebilir başka bir bağlamda çalışır, bu yüzden URL var oluşturmaya çalıştığınızda, istediğiniz blob değil boş bir nesne var.

Bunu çözmek için var olan birçok yoldan biri şöyledir:

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

İstek hazır olduğunda, aşağıdaki gibi tanımlanan "downloadFile" işlevini çağırır:

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

blob mükemmel bir şekilde oluşturulmuştur ve bu nedenle URL var, yeni pencereyi açmazsa lütfen 'rxjs / Rx' dosyasını zaten içe aktarıp almadığınızı kontrol edin;

  import 'rxjs/Rx' ;

umuyorum ki bu sana yardım edebilir.


9
Nedir this._reportService.getReport()ve ne geri döner?
Burjua

3
@Burjua getReport()dönüşleri athis.http.get(PriceConf.download.url)
ji-ruh

6
Yaşadığım sorun, pencerenin dosyayı indirmeden hemen açılıp kapanması
Braden Brown

7
Burada dosya adını nasıl ayarlayabiliriz? varsayılan olarak ad olarak sayısal bir değer seçer
Saurabh

8
API yanıt dosya indirmek için yukarıdaki kodu kullandım ama Blob bölüm oluşturmada bazı hata alıyorum "Tip yanıt Blobpart tipine atanamaz". Herkes bu sorunu bilir lütfen yardım
knbibin

92

Deneyin bu !

1 - Show save / open dosya pop-up'ı için bağımlılıkları yükleyin

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

2- Verileri almak için bu fonksiyonla bir servis oluşturun

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- Bileşende blob'u 'dosya koruyucu' ile ayrıştırın

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

  this.myService.downloadFile(this.id).subscribe(blob => {
            importedSaveAs(blob, this.fileName);
        }
    )

Bu benim için çalışıyor!


1
Adım 2 @ @Alejandro yanıtı ile birlikte kullandım ve dosya tasarrufu yüklemeye gerek kalmadan çalıştı ...
Ewert

5
Teşekkür ederim! Mükemmel çalışıyor! Yanıtın başlığında tanımlanan dosya adını alıp alamayacağımızı merak ediyorum. Mümkün mü?
jfajunior

2
hatası Av5 'RequestOptions' türünün bağımsız değişkeni, '{headers? türündeki parametreye atanamaz: HttpHeaders | {[header: string]: string | dize []; };
giveJob

Ancak bu büyük dosyaların indirilmesi için uygun değildir.
Reven

61

İstekte üstbilgi eklemeniz gerekmiyorsa , Angular2'de bir dosya indirmek için basit bir işlem yapabilirsiniz :

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

bileşeninizde.


4
Birisi bu cevabın neden reddedildiğini söyleyebilir mi? Konu angular2 kullanarak bir dosya indirmektir. Bu yöntem basit bir indirme yapmak için çalışıyorsa, geçerli bir cevap olarak da işaretlenmelidir.
Saurabh Shetty

5
@SaurabhShetty, Özel üstbilgiler göndermek istemeniz durumunda bu yardımcı olmaz, örneğin bir kimlik kartı göndermek isterseniz ne olur? OP sorusuna bakarsanız onun kullandığını görebilirsiniz authHttp!
A.Akram

6
Downvotes anlıyorum, yine de bu cevap benim sorunumu çözdü.
JoeriShoeby

1
Sunucunun URL'yi bir bağlamda döndürmesine izin verirseniz, sunucu URL'yi hazırlayabilir. ör .: nesne: MyRecord.Cover. Kapak, sunucudaki bir görüntünün URL'si olabilir. Get (Myrecord) öğesini çağırırken, sunucunun güvenlik belirteci ve diğer üstbilgiler ayarlanmış olarak hazırlanan url'yi (Kapak) döndürmesine izin verirsiniz.
Jens Alenius

2
Bu işe yarayan bir cevaptır. Sadece cevap vermeyen <yararlı özellik ekle> olmadığından emin olun.
gburton

47

Bu, HttpClient ve dosya tasarrufu kullanarak nasıl yapılacağını arayan kişiler içindir:

  1. Dosya tasarrufunu yükle

npm yükleme dosya tasarrufu - kaydetme

npm install @ types / dosya tasarrufu - kaydetme

API Hizmet sınıfı:

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

Bileşen:

import { saveAs } from 'file-saver';
exportPdf() {
    this.api_service.export().subscribe(data => saveAs(data, `pdf report.pdf`));
}

1
İndirme başladığında dosya boyutunu tarayıcıda nasıl gösterebilirim? Dosya boyutunu http başlığında içerik uzunluğu olarak gönderiyorum.
humbleCoder

35

Buna ne dersin?

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();
        })

Onunla yapabilirim.
ek pakete gerek yok.


3
Çok basit ama kusursuz bir şekilde çalışıyor. DOM'u karıştırmaz, herhangi bir öğe oluşturmaz. Bu çözümü yukarıdaki bazılarıyla birleştirdim ve bir cazibe gibi çalışıyor.
Chax

20

Alejandro Corredor'un belirttiği gibi basit bir kapsam hatasıdır. subscribeUyumsuz çalıştırılan veopen böylece veri yüklenmesi bittikten biz indir tetikleyebilir zaman, bu bağlamda yerleştirilmelidir.

Bununla birlikte, bunu yapmanın iki yolu vardır. Dokümanların önerdiği gibi, hizmet veri alma ve haritalama ile ilgilenir:

//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);
}

Daha sonra, bileşen üzerinde sadece haritalanan verilerle abone oluruz ve ilgileniriz. İki olasılık vardır. Birincisi , orijinal gönderide önerildiği gibi, ancak Alejandro tarafından belirtildiği gibi küçük bir düzeltmeye ihtiyaç duyuyor:

//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.'));
  }

İkinci yol FileReader kullanmaktır. Mantık aynıdır, ancak FileReader'ın verileri yüklemesini, iç içe geçmesini engelleyip zaman uyumsuz sorunu çözmesini açıkça bekleyebiliriz.

//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');
  }
}

Not: Bir Excel dosyası indirmeye çalışıyorum ve indirme tetiklenmiş olsa da (bu soruya cevap veriyor), dosya bozuk. Bu yayına verilen cevaba bakınız için bozuk dosyayı kaçınarak.


7
Ben dosya bozulma nedeni resblob yüklüyor ve aslında istediğiniz olduğunu düşünüyorum res._body. Ancak _bodyözel bir değişkendir ve erişilemez. Bugün itibariyle .blob()ve .arrayBuffer()bir http yanıt nesnesi üzerinde Açısal 2 uygulanmadı text()ve json()sadece iki seçenek ancak her ikisi de vücudunuzu gargara olacak. Bir çözüm buldun mu?
sschueller

1
merhaba @rll, yukarıdaki adımları izledi ve tamamlanan olarak abone alıyorum. Yine de indirilen dosyayı göremedim. Ben de herhangi bir hata göremedim. Lütfen yardım
AishApp

1
2 seçenek dosyayı indirmeme izin veriyor, ancak önce verileri arka planda yüklüyor. İndirilmesi gereken büyük bir dosyam varsa ne olur?
f123

1
Benim çözümüm sadece <a href=""></a>bir dosyayı indirmek için kullanmak .
user2061057

1
Bunun eski bir cevap olduğunu biliyorum, ancak arama sonuçlarında yüksek ve kabul edilen cevap: `headers.append ('responseType', 'arraybuffer');` `yanlış. Bu bir seçenek, başlık değil. Lütfen düzeltin. Aaaand ... Başlıklar oluşturulur ve kullanılmaz. Yararlı değil.
Stevo

17

Açısal 2.4.x için * .zip çözümünü indirin: ResponseContentType öğesini '@ angular / http' den içe aktarmanız ve responseType öğesini ResponseContentType.ArrayBuffer olarak değiştirmeniz gerekir (varsayılan olarak 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']);
}

16

Daha yeni açısal sürümler için:

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');
  });

Teşekkürler, Açısal 8 ile çalışır. Bunun neden bu kadar zor olduğunu bilmiyorum.
MDave

11

Dosyayı ajax ile indirmek her zaman acı verici bir süreçtir ve bence sunucu ve tarayıcının içerik türü müzakerelerinin bu işini yapmasına izin vermek en iyisidir.

Bence sahip olmak en iyisi

<a href="api/sample/download"></a> 

yapmak için. Bu, herhangi bir yeni pencere açılmasını ve bunun gibi şeyleri bile gerektirmez.

Numunenizdeki gibi MVC kontrol cihazı aşağıdaki gibi olabilir:

[HttpGet("[action]")]
public async Task<FileContentResult> DownloadFile()
{
    // ...
    return File(dataStream.ToArray(), "text/plain", "myblob.txt");
}

1
Haklısınız, ancak tek sayfalık uygulamadaki sunucu hatalarını nasıl yönetebilirsiniz? Bir hata durumunda, normalde, bir REST hizmeti hata ile JSON döndürür, böylece uygulamanın JSON'u başka bir tarayıcı penceresinde açmasına neden olur, bu da kullanıcının görmek istediği şey değildir
Luca

2
Bir erişim belirteciniz varsa, bunu sağlamanız gerekir
chris31389

Bu sade ve basit. Ancak, kimlik doğrulaması yapmak istiyorsanız, bir kerelik jeton gibi bir şeye sahip olma olasılığı vardır. Yani, bunun yerine, şu URL'ye sahip olabilirsiniz: example.com/myuri/report?tokenid=1234-1233 Ve veritabanındaki belirteç kimliğini doğrulayın. Tabii ki bu basit bir senaryo değil ve tüm durumlarda çalışır, ancak bir akış olarak rapor dönmeden önce veritabanına erişim var durumda bir çözüm olabilir ..
GingerBeer

İndirme URL'sini sunucudan alın. Böylece sunucu URL'yi bir kerede güvenlik belirteci ile hazırlayabilir.
Jens Alenius

8

4.3 httpClient nesnesiyle Açısal 4 kullanıyorum. Js Teknik Blogu'nda bulduğum bir bağlantı nesnesi oluşturan, indirmeyi yapmak için kullanan ve daha sonra yok eden bir yanıtı değiştirdim.

Müşteri:

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.')
        }); 

} 

This.downloadUrl değeri daha önce API'yi gösterecek şekilde ayarlanmıştı. Ekleri indirmek için kullanıyorum, bu yüzden id, contentType ve dosya adını biliyorum: Dosyayı döndürmek için bir MVC api kullanıyorum:

 [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;
        } 
    } 

Ataşman sınıfı şuna benzer:

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

Disk belleği deposu dosyayı veritabanından döndürür.

Umarım bu birine yardımcı olur :)


7

Redux Desenini kullananlar için

Yanıtında @Hector Cuevas adlı dosya tasarrufuna ekledim. Angular2 s. 2.3.1 kullanarak, @ types / file saver içine eklemem gerekmiyordu.

Aşağıdaki örnek bir günlüğü PDF olarak indirmektir.

Dergi işlemleri

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 }
 };
}

Dergi efektleri

@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'))

Dergi hizmeti

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

HTTP hizmeti

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

Dergi düşürücü Bu sadece uygulamamızda kullanılan doğru durumları ayarlamasına rağmen, yine de tüm deseni göstermek için eklemek istedim.

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: [] });
}

Umarım bu yardımcı olur.


7

Bana yardımcı olan çözümü paylaşıyorum (herhangi bir gelişme büyük beğeni topluyor)

Senin üzerinde hizmet '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'));
}

Bileşen Bölümü:

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);
}

Bileşen kısmında, bir yanıta abone olmadan hizmeti çağırırsınız. OpenOffice mime türlerinin tam listesi için abone olun: http://www.openoffice.org/framework/documentation/mimetypes/mimetypes.html


7

İçinizdeki yeni yöntemi çağırmayı denerseniz daha iyi olur subscribe

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

İç downloadFile(data)fonksiyon yapmamız gerekiyorblock, 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);
    }
}

5

PDF dosyalarını indirmek ve göstermek için , çok benzer bir kod kesildi aşağıdaki gibidir:

  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!")
      );
  }

5

İşte benim durumumda yaptığım bir şey -

// 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"));
}

Çözüme - buradan


4

Adım 2 için Hector'un cevabını dosya tasarrufu ve HttpClient kullanarak güncelleyin:

public downloadFile(file: File): Observable<Blob> {
    return this.http.get(file.fullPath, {responseType: 'blob'})
}

3

Bahar mvc ve açısal 2 kullanarak açısal 2'den bozulmadan indirmek için bir çözüm buldum

1 - benim dönüş türü: - Java sonundan ResponseEntity . Burada bayt [] dizisi denetleyiciden dönüş türü var gönderiyorum.

2. - Dosya koruyucunuzu çalışma alanınıza dizin sayfasına eklemek için:

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

3. bileşen ts'de bu kodu yazın:

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');

                });

Bu size xls dosya biçimini verecektir. Diğer formatları istiyorsanız, doğru uzantı ile mediatype ve dosya adını değiştirin.


3

Bugün aynı davaya bakıyordum, ek olarak bir pdf dosyası indirmek zorunda kaldım (dosya tarayıcıda işlenmemeli, bunun yerine indirilmelidir). Bunu başarmak için dosyayı Açısal olarak almam Blobve aynı zamanda Content-Dispositionyanıtta bir başlık eklemem gerektiğini keşfettim .

Bu alabildiğim en basitti (Açısal 7):

Hizmetin içinde:

getFile(id: String): Observable<HttpResponse<Blob>> {
  return this.http.get(`./file/${id}`, {responseType: 'blob', observe: 'response'});
}

Sonra, dosyayı bir bileşende indirmem gerektiğinde, şunları yapabilirsiniz:

fileService.getFile('123').subscribe((file: HttpResponse<Blob>) => window.location.href = file.url);

GÜNCELLEME:

Gereksiz başlık ayarı hizmetten kaldırıldı


Window.open yerine window.location.href kullanırsam Chrome bunu birden fazla dosya indirmesi olarak görür.
DanO

başlıkta yetkilendirme jetonunuz varsa bu çalışmaz
garg10may

3

Aşağıdaki kod benim için çalıştı

let link = document.createElement('a');
link.href = data.fileurl; //data is object received as response
link.download = data.fileurl.substr(data.fileurl.lastIndexOf('/') + 1);
link.click();

2

Şu ana kadar verilen cevapların yanı sıra içgörüler ve uyarılar da buldum. IE10 + ile uyumsuzlukları izleyebilir ve izlemelisiniz (eğer ilgilenirseniz).

Bu, uygulama bölümü ve hizmet bölümünden sonraki tam örnektir. Gözlem adını ayarladığımızı unutmayın : dosya adının başlığını yakalamak için. Ayrıca, Content-Disposition üstbilgisinin sunucu tarafından ayarlanması ve gösterilmesi gerektiğini unutmayın, aksi takdirde geçerli Açısal HttpClient bunu iletmez. Aşağıda bunun için bir dotnet çekirdek kodu ekledim .

public exportAsExcelFile(dataId: InputData) {
    return this.http.get(this.apiUrl + `event/export/${event.id}`, {
        responseType: "blob",
        observe: "response"
    }).pipe(
        tap(response => {
            this.downloadFile(response.body, this.parseFilename(response.headers.get('Content-Disposition')));
        })
    );
}

private downloadFile(data: Blob, filename: string) {
    const blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8;'});
    if (navigator.msSaveBlob) { // IE 10+
        navigator.msSaveBlob(blob, filename);
    } else {
        const link = document.createElement('a');
        if (link.download !== undefined) {
            // Browsers that support HTML5 download attribute
            const url = URL.createObjectURL(blob);
            link.setAttribute('href', url);
            link.setAttribute('download', filename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
    }
}

private parseFilename(contentDisposition): string {
    if (!contentDisposition) return null;
    let matches = /filename="(.*?)"/g.exec(contentDisposition);

    return matches && matches.length > 1 ? matches[1] : null;
}

Dotnet çekirdeği, Content-Disposition ve MediaType ile

 private object ConvertFileResponse(ExcelOutputDto excelOutput)
    {
        if (excelOutput != null)
        {
            ContentDisposition contentDisposition = new ContentDisposition
            {
                FileName = excelOutput.FileName.Contains(_excelExportService.XlsxExtension) ? excelOutput.FileName : "TeamsiteExport.xlsx",
                Inline = false
            };
            Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
            Response.Headers.Add("Content-Disposition", contentDisposition.ToString());
            return File(excelOutput.ExcelSheet, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        }
        else
        {
            throw new UserFriendlyException("The excel output was empty due to no events.");
        }
    }

1
 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();
                });

1

Basitçe aşağıdaki urlgibi koyun href.

<a href="my_url">Download File</a>

Çalışıyor mu? Hata alıyorum ... "HATA TypeError:" Komut dosyasından 'file: ///Downloads/test.json' 'a erişim reddedildi. ""
Jay

Teşekkürler u pls paylaşmak ur url nasıl görünüyor? Dosya protokolü veya http veya başka bir şey mi?
Jay

Dosya protokolü.
Harunur Rashid


1

Ayrıca, indirme özniteliğini kullandığınız şablondan doğrudan bir dosya indirebilir [attr.href]ve bileşenden bir özellik değeri sağlayabilirsiniz. Bu basit çözüm çoğu tarayıcıda çalışmalıdır.

<a download [attr.href]="yourDownloadLink"></a>

Referans: https://www.w3schools.com/tags/att_a_download.asp


1
SO hoş geldiniz! Lütfen (dizgi ve dilbilgisi) düzeltmelerimin yararlı olup olmadığını kontrol edin.
B - rian

0

Parametreleri yalnızca bir URL'ye gönderirseniz, bunu şu şekilde yapabilirsiniz:

downloadfile(runname: string, type: string): string {
   return window.location.href = `${this.files_api + this.title +"/"+ runname + "/?file="+ type}`;
}

parametreleri alan hizmette


0

Bu yanıt, öncelikle güvenlik nedeniyle dosyaları AJAX ile doğrudan indiremeyeceğinizi göstermektedir. Bu durumda ne yaptığımı anlatacağım,

01. Bağlantıhref etiketinize component.htmldosyanın içine nitelik ekleyin ,
örneğin: -

<div>
       <a [href]="fileUrl" mat-raised-button (click)='getGenaratedLetterTemplate(element)'> GENARATE </a>
</div>

02.component.ts Güvenlik seviyesini atlamak ve açılır pencere olarak kaydet diyalog penceresini getirmek için aşağıdaki tüm adımları gerçekleştirin
:

import { environment } from 'environments/environment';
import { DomSanitizer } from '@angular/platform-browser';
export class ViewHrApprovalComponent implements OnInit {
private apiUrl = environment.apiUrl;
  fileUrl
 constructor(
    private sanitizer: DomSanitizer,
    private letterService: LetterService) {}
getGenaratedLetterTemplate(letter) {

    this.data.getGenaratedLetterTemplate(letter.letterId).subscribe(
      // cannot download files directly with AJAX, primarily for security reasons);
    console.log(this.apiUrl + 'getGeneratedLetter/' + letter.letterId);
    this.fileUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.apiUrl + 'getGeneratedLetter/' + letter.letterId);
  }

Not: Durum kodu 200 ile "Tamam" hatası alıyorsanız, bu cevap işe yarar


0

Eh, sunucunun bir içerik düzenleme başlığına sahip bir dosya gönderdiğinde, rxjs ve açısal hariç herhangi bir üçüncü taraf yüklemesi olmadan çoğu senaryoda kolayca çalışması gereken yukarıdaki cevapların çoğundan esinlenen bir kod parçası yazdım.

İlk olarak, bileşen dosyanızdan kodu nasıl çağırırsınız

this.httpclient.get(
   `${myBackend}`,
   {
      observe: 'response',
      responseType: 'blob'
   }
).pipe(first())
.subscribe(response => SaveFileResponse(response, 'Custom File Name.extension'));

Gördüğünüz gibi, temelde iki değişiklikle açısaldan ortalama arka uç çağrısı

  1. Beden yerine yanıtı gözlemliyorum
  2. Yanıtın bir leke olduğu konusunda net davranıyorum

Dosya sunucudan getirildikten sonra, prensip olarak, dosyayı ayrı bir dosyada tuttuğum yardımcı fonksiyona kaydetme görevini devrediyorum ve hangi bileşene ihtiyacım olursa içeri aktarıyorum

export const SaveFileResponse = 
(response: HttpResponse<Blob>, 
 filename: string = null) => 
{
    //null-checks, just because :P
    if (response == null || response.body == null)
        return;

    let serverProvidesName: boolean = true;
    if (filename != null)
        serverProvidesName = false;

    //assuming the header is something like
    //content-disposition: attachment; filename=TestDownload.xlsx; filename*=UTF-8''TestDownload.xlsx
    if (serverProvidesName)
        try {
            let f: string = response.headers.get('content-disposition').split(';')[1];
            if (f.includes('filename='))
                filename = f.substring(10);
        }
        catch { }
    SaveFile(response.body, filename);
}

//Create an anchor element, attach file to it, and
//programmatically click it. 
export const SaveFile = (blobfile: Blob, filename: string = null) => {
    const a = document.createElement('a');
    a.href = window.URL.createObjectURL(blobfile);
    a.download = filename;
    a.click();
}

Artık şifreli GUID dosya adları yok! Sunucunun sağladığı herhangi bir adı, istemcide açıkça belirtmek zorunda kalmadan kullanabilir veya sunucu tarafından sağlanan dosya adının üzerine yazabiliriz (bu örnekte olduğu gibi). Ayrıca, ihtiyaç duyulması halinde dosya adını içerik düzeninden çıkarma algoritmasını kolayca değiştirebilir ve diğer her şey etkilenmeyecektir - bu tür bir çıkarma sırasında bir hata olması durumunda 'boş' iletilecektir. dosya adı olarak.

Başka bir cevabın işaret ettiği gibi, IE her zamanki gibi özel bir tedaviye ihtiyaç duyuyor. Ancak krom kenarı birkaç ay içinde gelirken, yeni uygulamalar geliştirirken endişelenmeyeceğim (umarım). URL'yi iptal etme meselesi de var, ancak bunun hakkında biraz emin değilim, bu yüzden birisi yorumlarda buna yardımcı olabilirse, bu harika olurdu.


0

Bir sekme bir şey indirmeden açılır ve kapanırsa, sahte bağlantı ile takip etmeyi denedim ve çalıştı.

downloadFile(x: any) {
var newBlob = new Blob([x], { type: "application/octet-stream" });

    // 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(newBlob);
      return;
    }

    // For other browsers: 
    // Create a link pointing to the ObjectURL containing the blob.
    const data = window.URL.createObjectURL(newBlob);

    var link = document.createElement('a');
    link.href = data;
    link.download = "mapped.xlsx";
    // this is necessary as link.click() does not work on the latest firefox
    link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));

    setTimeout(function () {
      // For Firefox it is necessary to delay revoking the ObjectURL
      window.URL.revokeObjectURL(data);
      link.remove();
    }, 100);  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.