Angular2 이상으로 파일을 다운로드하는 방법


182

angular2 클라이언트를 개발하는 WebApi / MVC 앱이 있습니다 (MVC를 대체하기 위해). Angular가 파일을 저장하는 방법을 이해하는 데 문제가 있습니다.

요청은 괜찮습니다 (MVC에서 잘 작동하고 수신 된 데이터를 기록 할 수 있음). 다운로드 된 데이터를 저장하는 방법을 알 수 없습니다 (주로이 게시물 과 동일한 논리를 따르고 있습니다 ). 나는 그것이 어리석게 간단하다는 것을 확신하지만, 지금까지 나는 그것을 이해하지 못한다.

구성 요소 기능의 코드는 다음과 같습니다. 나는 블롭 방법까지 내가 이해로가는 방법이어야한다, 다른 대안을 시도했습니다,하지만 기능은 없습니다 createObjectURLURL. URL창 에서 정의조차 찾을 수 없지만 분명히 존재합니다. FileSaver.js모듈을 사용하면 동일한 오류가 발생합니다. 그래서 이것은 최근에 변경되었거나 아직 구현되지 않은 것 같습니다. 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);
}

완벽을 기하기 위해 데이터를 가져 오는 서비스는 아래에 있지만, 요청이 있으면 요청을 발행하고 데이터가 성공하면 매핑하지 않고 데이터를 전달하는 것입니다.

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

이 방법으로는 큰 파일을 다운로드 할 수 없습니다. 탭당 메모리 제한에 도달합니다. 1-2GB 정도로 낮을 수 있습니다.
Matthew B.

@MatthewB. 더 나은 것을 말했으면 좋겠다.
steve

큰 파일 다운로드의 경우 <A> 클릭을 시뮬레이션하는 경우 대상이 "_blank"와 같거나 양식 제출을 수행하는 경우 새 탭을 지정해야합니다. Ajax 스타일 요청으로 큰 파일 크기 제한을 해결할 수있는 확실한 방법이 없다고 생각합니다.
Matthew B.

답변:


181

문제는 Observable이 다른 컨텍스트에서 실행되므로 URL var를 만들려고 할 때 원하는 얼룩이 아닌 빈 개체가 있다는 것입니다.

이를 해결하기 위해 존재하는 많은 방법 중 하나는 다음과 같습니다.

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

요청이 준비되면 다음과 같이 정의 된 "downloadFile"함수를 호출합니다.

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

Blob이 완벽하게 생성되었으므로 URL var, 새 창이 열리지 않으면 이미 'rxjs / Rx'를 가져 왔는지 확인하십시오.

  import 'rxjs/Rx' ;

이것이 당신을 도울 수 있기를 바랍니다.


9
무엇 this._reportService.getReport()이며 무엇을 반환합니까?
부르주아

3
@Burjua는 getReport()반환this.http.get(PriceConf.download.url)
ji-ruh

6
내가 겪고있는 문제는 파일을 다운로드하지 않고 창이 열리고 닫히는 것입니다.
Braden Brown

7
여기서 파일 이름을 어떻게 설정할 수 있습니까? 기본적으로 숫자 값을 이름으로 선택합니다
Saurabh

8
API 응답에서 파일을 다운로드하기 위해 위의 코드를 사용했지만 Blob 부분 "Blobpart 유형에 유형 응답을 지정할 수 없습니다"를 작성하는 중에 오류가 발생합니다. 이 문제를 아는 사람이 있으면
친절히

92

이것을 보십시오 !

1-쇼 저장 / 열기 파일 팝업에 대한 설치 종속성

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

2-이 기능으로 데이터를 수신하는 서비스를 만듭니다.

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- 구성 요소에서 'file-saver'로 blob을 구문 분석하십시오.

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

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

이것은 나를 위해 작동합니다!


1
나는 @Alejandro의 답변과 함께 2 단계를 사용했으며 파일 보호기를 설치할 필요없이 작동했습니다 ...
Ewert

5
감사합니다! 완벽하게 작동합니다! 응답 헤더에 정의 된 파일 이름을 얻을 수 있는지 궁금합니다. 가능합니까?
jfajunior

2
오류 Av5 'RequestOptions'유형의 인수를 '{헤더 유형의 매개 변수에 지정할 수 없습니까? : HttpHeaders | {[헤더 : 문자열] : 문자열 | 끈[]; };
giveJob

그러나 이것은 큰 파일 다운로드에는 적합하지 않습니다.
Reven

61

요청 에 헤더를 추가하지 않아도 Angular2에서 파일을 다운로드하려면 간단한 작업을 수행 할 수 있습니다 .

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

당신의 구성 요소에서.


4
누군가이 답변이 다운 보트 된 이유를 말해 줄 수 있습니까? 주제는 angular2를 사용하여 파일을 다운로드하는 것입니다. 이 방법으로 간단한 다운로드가 가능하면 유효한 답변으로 표시되어야합니다.
Saurabh Shetty

5
@SaurabhShetty, 사용자 정의 헤더를 보내려는 경우 도움이되지 않습니다. 예를 들어 인증 토큰을 보내려면 어떻게해야합니까? OP 질문을 살펴보면 그가 사용하는 것을 볼 수 있습니다 authHttp!
A.Akram

6
나는 downvotes를 이해하지만이 답변으로 내 문제가 해결되었습니다.
JoeriShoeby

1
일부 컨텍스트에서 서버가 URL을 리턴하게하면 서버가 URL을 준비 할 수 있습니다. 예 : 개체 : MyRecord.Cover. 표지는 서버의 이미지에 대한 URL 일 수 있습니다. get (Myrecord)을 호출하면 보안 토큰 및 기타 헤더가 설정된 상태에서 서버가 준비된 URL (커버)을 반환 할 수 있습니다.
Jens Alenius

2
작동하는 답입니다. 응답하지 않는 <여기에 유용한 기능 삽입>이 없기 때문에주의하십시오.
gburton

47

이것은 HttpClient 및 파일 보호기를 사용하여 수행하는 방법을 찾는 사람들을위한 것입니다.

  1. 파일 세이버 설치

npm 설치 파일 보호기 --save

npm install @ types / file-saver --save

API 서비스 클래스 :

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

구성 요소:

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

1
다운로드가 시작될 때 브라우저에 파일 크기를 표시하는 방법은 무엇입니까? http 헤더에서 파일 크기를 content-length로 보냅니다.
humbleCoder

35

이건 어때요?

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

나는 그것으로 할 수 있습니다.
추가 패키지가 필요하지 않습니다.


3
매우 간단하지만 완벽하게 작동합니다. DOM을 어지럽히 지 않고 요소를 만들지 않습니다. 이 솔루션을 위의 일부와 결합하여 매력처럼 작동합니다.
Chax

20

Alejandro Corredor가 언급했듯이 간단한 범위 오류입니다. 는 subscribe비동기 적으로 실행되고,이 open때문에 데이터가로드를 완료하는 것이 우리가 다운로드를 트리거 할 때, 그 컨텍스트에 배치해야합니다.

즉, 두 가지 방법이 있습니다. 문서에서 권장하는대로 서비스는 데이터를 가져오고 매핑합니다.

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

그런 다음 구성 요소에서 매핑 된 데이터를 구독하고 처리합니다. 두 가지 가능성이 있습니다. 첫 번째 는 원래 게시물에서 제안되었지만 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.'));
  }

두 번째 방법은 FileReader를 사용하는 것입니다. 논리는 동일하지만 FileReader가 데이터를로드하고 중첩을 피하고 비동기 문제를 해결하기 위해 명시 적으로 기다릴 수 있습니다.

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

참고 : Excel 파일을 다운로드하려고하는데 다운로드가 트리거 되어도 질문에 대답하지만 파일이 손상되었습니다. 손상된 파일피하려면 이 게시물에 대한 답변을 참조하십시오 .


7
파일이 손상된 이유 res는 BLOB에 로드 하고 실제로 원하기 때문 res._body입니다. 그러나 _body개인 변수이며 액세스 할 수 없습니다. 오늘로서 .blob().arrayBuffer()HTTP에 응답 객체는 각도 2에 구현되지 않은 text()json()있는 두 옵션을하지만 모두가 몸을 V 곡합니다. 해결책을 찾았습니까?
sschueller

1
안녕 @rll, 위의 단계를 수행하고 완료로 구독 받고 있습니다. 여전히 파일이 다운로드되는 것을 볼 수 없습니다. 나는 또한 오류를 볼 수 없었다. 도와주세요
AishApp

1
두 가지 옵션을 사용하면 파일을 다운로드 할 수 있지만 먼저 백그라운드에서 데이터를로드합니다. 다운로드해야하는 큰 파일이 있으면 어떻게합니까?
f123

1
내 솔루션은 <a href=""></a>파일을 다운로드하는 데 사용 하는 것입니다.
user2061057

1
나는 이것이 오래된 대답이라는 것을 알고 있지만 검색 결과가 높으며 허용되는 대답입니다.`headers.append ( 'responseType', 'arraybuffer');`행이 잘못되었습니다. 헤더가 아닌 옵션입니다. 고쳐주세요. Aaaand ... 헤더가 생성되어 사용되지 않습니다. 도움이되지 않습니다.
Stevo

17

각도 2.4.x 용 * .zip 솔루션 다운로드 : '@ angular / http'에서 ResponseContentType을 가져오고 responseType을 ResponseContentType.ArrayBuffer로 변경해야합니다 (기본적으로 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

최신 각도 버전의 경우 :

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

감사합니다. Angular 8에서 작동합니다. 왜 이렇게 찾기 어려운지 모릅니다.
MDave

11

아약스를 통해 파일을 다운로드하는 것은 항상 고통스러운 과정이며 서버와 브라우저가 콘텐츠 유형 협상 작업을 수행하는 것이 가장 좋습니다.

나는 최선을 다한다고 생각합니다

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

그것을하기 위해. 이것은 심지어 새로운 창문을 열거 나 그런 것들을 필요로하지 않습니다.

샘플과 같은 MVC 컨트롤러는 다음과 같습니다.

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

1
맞습니다. 그러면 단일 페이지 응용 프로그램에서 서버 오류를 어떻게 관리 할 수 ​​있습니까? 오류가 발생하는 경우 일반적으로 REST 서비스는 오류와 함께 JSON을 리턴하므로 애플리케이션이 다른 브라우저 창에서 JSON을 열게되므로 사용자가보고 싶지 않은 것
Luca

2
액세스 토큰이 있으면 작동하지 않습니다.
chris31389

이것은 평범하고 간단합니다. 그러나 인증을 원한다면 일회성 토큰과 같은 가능성이 있습니다. 따라서 이와 같이 사용하는 대신 URL을 example.com/myuri/report?tokenid=1234-1233 로 설정하고 데이터베이스에서 토큰 ID를 확인하십시오. 물론 간단한 시나리오는 아니며 모든 상황에서 작동하지만 보고서를 스트림으로 반환하기 전에 데이터베이스에 액세스 할 수있는 상황에서는 솔루션이 될 수 있습니다.
GingerBeer

서버에서 다운로드 URL을 가져옵니다. 따라서 서버는 일회용 보안 토큰으로 URL을 준비 할 수 있습니다.
Jens Alenius

8

4.3 httpClient 객체와 함께 Angular 4를 사용하고 있습니다. Js의 기술 블로그에서 찾은 답변을 수정하여 링크 객체를 생성하고 링크를 사용하여 다운로드를 수행 한 다음 파괴합니다.

고객:

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의 값은 이전에 API를 가리 키도록 설정되었습니다. 이것을 사용하여 첨부 파일을 다운로드하고 있으므로 id, contentType 및 filename을 알고 있습니다. 파일을 반환하기 위해 MVC API를 사용하고 있습니다.

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

부착 클래스는 다음과 같습니다.

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

filerep 저장소는 데이터베이스에서 파일을 리턴합니다.

희망이 누군가에게 도움이되기를 바랍니다 :)


7

Redux 패턴을 사용하는 경우

나는 그의 답변에 이름이 붙은 @Hector Cuevas로 파일 저장기에 추가했습니다. Angular2 v. 2.3.1을 사용하면 @ types / file-saver를 추가 할 필요가 없었습니다.

다음 예는 저널을 PDF로 다운로드하는 것입니다.

저널 액션

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

저널 효과

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

저널 서비스

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

HTTP 서비스

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

저널 리듀서 이것은 응용 프로그램에 사용 된 올바른 상태 만 설정하지만 완전한 패턴을 보여주기 위해 여전히 추가하려고했습니다.

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

도움이 되길 바랍니다.


7

나는 나를 도운 해결책을 공유합니다 (모든 개선은 대단히 감사합니다)

귀하의 서비스 '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'));
}

구성 부품 :

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

구성 요소 부분에서는 응답을 구독하지 않고 서비스를 호출합니다. openOffice mime 유형의 전체 목록은 http://www.openoffice.org/framework/documentation/mimetypes/mimetypes.html을 참조하십시오.


7

내부의 새로운 메소드를 호출하려고하면 더 좋습니다. subscribe

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

downloadFile(data)우리가해야 할 내부 기능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);
    }
}

5

PDF 파일 을 다운로드하여 표시하려면 다음과 같이 매우 비슷한 코드를 가져옵니다.

  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

여기에 내가 한 일이 있습니다.

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

해결책은 여기 에서 참조됩니다 -here


4

2 단계에서 파일 저장 기와 HttpClient를 사용하여 Hector의 답변으로 업데이트하십시오.

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

3

스프링 mvc와 각도 2를 사용하여 손상되지 않고 각도 2에서 다운로드 할 수있는 솔루션을 얻었습니다.

1st- 내 반환 형식은 다음과 같습니다 - ResponseEntity 자바 끝에서. 여기에 byte [] 배열이 컨트롤러에서 반환 유형을 보내고 있습니다.

두 번째-색인 페이지의 작업 영역에 파일 보호기를 포함 시키려면 다음과 같이하십시오.

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

세 번째-구성 요소 ts 에서이 코드를 작성하십시오.

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

                });

xls 파일 형식이 제공됩니다. 다른 형식을 원하면 올바른 확장자로 미디어 유형과 파일 이름을 변경하십시오.


3

나는 오늘이 같은 사건에 직면 해 있었고, pdf 파일을 첨부 파일로 다운로드해야했습니다 (파일은 브라우저에서 렌더링되어서는 안되며 대신 다운로드되어야 함). 달성하기 위해 파일을 Angular로 가져와야 하며 응답에 헤더를 Blob추가 해야한다는 것을 알았습니다 Content-Disposition.

이것은 내가 얻을 수있는 가장 간단했습니다 (Angular 7) :

서비스 내부 :

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

그런 다음 구성 요소에서 파일을 다운로드해야 할 때 간단히 다음을 수행 할 수 있습니다.

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

최신 정보:

서비스에서 불필요한 헤더 설정 제거


window.open 대신 window.location.href를 사용하면 Chrome에서 여러 파일 다운로드로 취급합니다.
DanO 2016 년

이하지 않습니다 작품은 당신이있는 경우에 인증 토큰 헤더에 필요
garg10may

3

다음 코드는 나를 위해 일했습니다.

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

나는 지금까지 통찰력과 경고가 부족한 답을 찾았습니다. IE10 +와의 비 호환성을 관찰 할 수 있고주의해야합니다 (필요한 경우).

다음은 응용 프로그램 부분과 서비스 부분이 포함 된 완전한 예입니다. 파일 이름의 헤더를 잡기 위해 observe : "response" 를 설정했습니다 . 또한 Content-Disposition 헤더는 서버에서 설정하고 노출해야합니다. 그렇지 않으면 현재 Angular HttpClient가이를 전달하지 않습니다. 아래에 닷넷 코어 코드를 추가했습니다 .

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 코어

 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

아래와 url같이 간단히 넣으 href십시오.

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

작동합니까? 오류가 발생했습니다 ... "오류 TypeError :"스크립트에서 'file : ///Downloads/test.json'에 대한 액세스가 거부되었습니다. ""
Jay

감사합니다. U pls는 URL이 어떻게 생겼는지 공유 할 수 있습니까? 파일 프로토콜이나 http 또는 다른 것입니까?
Jay

파일 프로토콜입니다.
Harunur Rashid 2018


1

다운로드 속성을 사용하는 템플릿에서 직접 파일을 다운로드 [attr.href]하고 구성 요소에서 속성 값을 제공 할 수도 있습니다. 이 간단한 솔루션은 대부분의 브라우저에서 작동합니다.

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

참조 : https://www.w3schools.com/tags/att_a_download.asp


1
SO에 오신 것을 환영합니다! 내 (조판 및 문법) 수정이 도움이되는지 확인하십시오.
B--rian

0

매개 변수를 URL로만 보내는 경우 다음과 같이 수행 할 수 있습니다.

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

매개 변수를받는 서비스에서


0

답변은 주로 보안상의 이유로 AJAX로 직접 파일을 다운로드 할 수 없음을 나타냅니다. 이 상황에서 내가하는 일을 설명하겠습니다.

01. 파일 href안에 앵커 태그에 속성을 추가하십시오 .component.html

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

02.component.ts 보안 수준을 무시하고 다른 이름으로 저장 팝업 대화 상자를 표시하려면 다음 단계를 모두 수행하십시오
.

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

참고 :이 답변은 상태 코드 200으로 "OK"오류가 발생하는 경우 작동합니다


0

글쎄, 서버가 rxjs와 angular를 제외한 타사 설치없이 콘텐츠 처리 헤더가있는 파일을 보내는 대부분의 시나리오에서 쉽게 작동 해야하는 위의 많은 답변에서 영감을 얻은 코드를 작성했습니다.

먼저 컴포넌트 파일에서 코드를 호출하는 방법

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

보시다시피, 기본적으로 각도에서 평균 백엔드 호출은 거의 두 가지로 변경됩니다

  1. 나는 몸 대신에 반응을 관찰하고있다
  2. 응답이 blob이라는 것에 대해 명시 적입니다.

파일을 서버에서 가져 오면 원칙적으로 파일을 저장하는 전체 작업을 도우미 기능에 위임하여 별도의 파일로 유지하고 필요한 구성 요소로 가져옵니다.

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

더 이상 비밀 GUID 파일 이름이 없습니다! 클라이언트에서 서버를 명시 적으로 지정하지 않고 서버가 제공 한 이름을 사용하거나 서버가 제공 한 파일 이름을 덮어 쓸 수 있습니다 (이 예와 같이). 또한 필요에 따라 콘텐츠 처리에서 파일 이름을 추출하는 알고리즘을 필요에 맞게 쉽게 변경할 수 있으며 다른 모든 항목에는 영향을 미치지 않습니다. 추출 중에 오류가 발생하면 '널'을 전달합니다. 파일 이름으로.

다른 답변에서 이미 지적했듯이 IE는 항상 특별한 처리가 필요합니다. 그러나 크롬 에지가 몇 개월 만에 도착하면 새로운 앱을 구축하는 동안 걱정하지 않아도됩니다. URL을 해지 해야하는 문제도 있지만 그 점에 대해서는 확신이 들지 않으므로 누군가가 의견에서 도움을 줄 수 있다면 정말 좋을 것입니다.


0

아무것도 다운로드하지 않고 탭이 열리고 닫히면 모의 앵커 링크로 다음을 시도해 보았습니다.

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);  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.