【问题标题】:angular2 download file with post request带有发布请求的angular2下载文件
【发布时间】:2016-11-05 02:35:49
【问题描述】:

我有一个按钮定义为:

<button pButton type="button" label="Download" data-icon="fa-cloud-download" (click)="download()"></button>

download 方法委托给服务,服务通过 post 方法调用 api:

download(model:GlobalModel) {
        let downloadURL = base + "rest/process/download";
        let body = JSON.stringify(model);
        let headers = new Headers({'Content-Type': 'application/json'});
        let options = new RequestOptions({headers: headers});   

        this.http.post('http://localhost:48080/rest/process/download', body, options)
            .toPromise()
            .then(
                response => {
                    console.log(response);       
                    var mediaType = 'application/zip';
                    var blob = new Blob([response.blob()], {type: mediaType});
                    var filename = 'project.zip';
                    saveAs(blob, filename);//FileSaver.js libray
                });

    }

但是到目前为止blob() 方法还没有实现,还有其他使用_body 的答案,但是有一个打字稿错误,比如“_body 是私有的”。

浏览器显示下载窗口,但是当我下载文件时,文件已损坏且无法打开(我检查postman,文件已从服务器生成正常)。

我怎样才能正确下载文件?...如果不能,有可用的解决方法吗?

【问题讨论】:

  • 如果你这样做会发生什么:new Blob([response.text()], {type: mediaType})? text() 应该返回响应的原始正文,我相信..
  • .text() 创建一个损坏的文件

标签: download angular


【解决方案1】:

这是一个有效的精简示例 https://stackoverflow.com/a/42992377/3752172

将控制器修改为 POST:

[HttpPost("realisationsFilterExcel")]
public FileResult exportExcell([FromBody] FilterRealisation filter)
{
    var contentType = "application/octet-stream";
    HttpContext.Response.ContentType = contentType;

    PaginationSet<RealisationReportViewModel> itemsPage = _realisationRepository.GetRealisationReportFilter(filter, User);

    RealisationsReportExcell reportExcell = new RealisationsReportExcell();
    var filedata = reportExcell.GetReport(itemsPage);   
    FileContentResult result = new FileContentResult(filedata, contentType)
    {
        FileDownloadName = "report.xlsx"
    };
    return result;
}

需要 FileSaver 作为 dep:

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

修改方法 DownloadComponent angular2 为 POST

@Input() filter: any;

public downloadFilePost() {
        this.http.post(this.api, this.filter, { responseType: ResponseContentType.Blob })
        .subscribe(
        (response: any) => {
            let blob = response.blob();
            let filename = 'report.xlsx';
            FileSaver.saveAs(blob, filename);
        });
    }

使用

<download-btn [filter]="myFilter" api="api/realisations/realisationsFilterExcel"></download-btn>

【讨论】:

【解决方案2】:

我终于用答案中解释的技巧解决了:https://stackoverflow.com/a/37051365/2011421

我在这里描述一下我的特殊方法,以防万一:

download(model:GlobalModel) {
    // Xhr creates new context so we need to create reference to this
    let self = this;
    var pending:boolean = true;

    // Create the Xhr request object
    let xhr = new XMLHttpRequest();

    let url = BASE + "/download";
    xhr.open('POST', url, true);
    xhr.setRequestHeader("Content-type", "application/json");
    xhr.responseType = 'blob';

    // Xhr callback when we get a result back
    // We are not using arrow function because we need the 'this' context
    xhr.onreadystatechange = function () {

        // We use setTimeout to trigger change detection in Zones
        setTimeout(() => {
            pending = false;
        }, 0);

        // If we get an HTTP status OK (200), save the file using fileSaver
        if (xhr.readyState === 4 && xhr.status === 200) {
            var blob = new Blob([this.response], {type: 'application/zip'});
            saveAs(blob, 'project.zip');
        }
    };

    // Start the Ajax request
    xhr.send(JSON.stringify(model));
}

不幸的是,angular2 http 对象现在还不完整,这个解决方案虽然有用,但感觉很老套。

【讨论】:

    猜你喜欢
    • 2018-08-31
    • 2014-07-03
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2018-12-11
    相关资源
    最近更新 更多