【问题标题】:Angular2 download excel file from Web API, file is corruptAngular2从Web API下载excel文件,文件已损坏
【发布时间】:2017-01-20 19:30:51
【问题描述】:

我正在尝试下载使用 ClosedXML 创建的文件。我已经验证该文件没有损坏,但由于某种原因,它只适用于 Angular1,而不是 Angular2。返回文件的web api代码为:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new ByteArrayContent(ms.GetBuffer());
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
return response;

在 Angular2 中,在我的网络服务中:

let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('responseType', 'arrayBuffer');
this.observableDataGet = this._http.post(`${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, {headers: this.getHeaders()})
    .map(response => {
        if (response.status == 400) {
            return "FAILURE";
        } else if (response.status == 200) {
            var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
            var blob = new Blob([response.arrayBuffer()], { type: contentType });
            return blob;
        }
    })

在我的组件中:

.subscribe(blob => {
    var downloadUrl= URL.createObjectURL(blob);
    window.open(downloadUrl);
},

一个文件已下载,但当我尝试访问它时它已损坏,并且是使用 Angular1 下载时文件大小的两倍。

如果我用 Angular1 调用 SAME API,文件下载正常。

我的服务代码:

function generateMonthlySpreadsheet(header) {
    var request = $http({
        method: "post",
        responseType: 'arraybuffer',
        url: TEST_API_URL + 'Report/MonthlySpreadsheet',
        timeout: 30000,
        headers: header
    });
    return ( request.then(handleSuccess, handleError) );
}

handleSuccess 返回 response.data 的位置(对于 angular2 我无法获取)

以及调用服务的代码:

alertAppService.generateMonthlySpreadsheet(header).then(function (data){
    var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
    var objectUrl = URL.createObjectURL(blob);
    window.open(objectUrl);

有趣的是,在 Angular2 中,如果我只是将我的 web 服务更改为 GET(我想要 POST,但只是为了尝试一下)然后摆脱服务代码并简单地进行此调用,文件就可以了:

window.open(`${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, "_blank");

那么,真的,这里有什么区别?为什么相同或非常相似的代码适用于 Angular1 而不是 Angular2?

-- 卡伦

【问题讨论】:

    标签: angular


    【解决方案1】:

    我知道其他人也发现了同样的问题。我已经解决了,但必须切换到 xhr 才能正常工作。

    第一种方法是行不通的。我从上面稍微简化了一下:

        generateMonthlySpreadsheet2(searchCriteria: Object) {
            let headers = new Headers();
            headers.append('Content-Type', 'application/json');
            headers.append('responseType', 'blob');
    
            return this._http.post(`${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, {headers: headers})
                .map(response => {
                    if (response.status == 400) {
                        this.handleError;
                    } else if (response.status == 200) {
                        var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
                        var blob = new Blob([(<any>response)._body], { type: contentType });            // size is 89KB instead of 52KB
    //                    var blob = new Blob([(<any>response).arrayBuffer()], { type: contentType });  // size is 98KB instead of 52KB
    //                    var blob = new Blob([(<any>response).blob()], { type: contentType });         // received Error: The request body isn't either a blob or an array buffer
                        return blob;
                    }
                })
                .catch(this.handleError);
        }
    

    第二种方法确实有效:

    generateMonthlySpreadsheet(searchCriteria: Object): Observable<Object[]> {
        return Observable.create(observer => {
    
            let xhr = new XMLHttpRequest();
    
            xhr.open('POST', `${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, true);
            xhr.setRequestHeader('Content-type', 'application/json');
            xhr.responseType='blob';
    
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
    
                        var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
                        var blob = new Blob([xhr.response], { type: contentType });
                        observer.next(blob);
                        observer.complete();
                    } else {
                        observer.error(xhr.response);
                    }
                }
            }
            xhr.send();
    
        });
    }
    

    希望这对其他人有帮助!我在其他地方看到了这个问题,所以我也会在那里添加一个指向我的解决方案的链接。

    -- 卡伦

    【讨论】:

      【解决方案2】:

      这对我有用(确保服务确实发回 xlsx 文件作为响应):

      1. 安装这些依赖项以显示“保存文件”弹出窗口

        npm install file-saver --save-dev
        npm install @types/file-saver --save-dev
        
      2. 在您的服务中导入:

        import * as FileSaver from 'file-saver';
        
      3. 用法:

        downloadFile(): void {
            let url: string = “http://yourdomain.com/exports/excelExport.aspx”;
           let headers = new Headers({ 'Content-Type': 'application/json'} );
        
            //in case you have custom headers, else you can ignore this part
        headers.set('x-custom-header1', “some value”);
            headers.set('x-custom-header2', “some value2”);
        
            let options = new RequestOptions({responseType: ResponseContentType.Blob, headers });
        
            this.http.get(url, options)
                .map(res => res.blob())
                .subscribe(
                data => {
        FileSaver.saveAs(data, 'Export.xlsx'); 
                },
                err => {
                    console.log('error');
                    console.error(err);
                });
        }
        

      【讨论】:

        【解决方案3】:

        这是我用来 Dwobnload 带有样式(颜色..)的完整文件的解决方案

        WebApi:

         [HttpGet]
                [Route("api/RapproResult/DownloadExcelReport/{reportName}")]
                public HttpResponseMessage DownloadExcelReport( string reportName)
                {
        
        
                    try
                    {
                         string filePath = HttpContext.Current.Server.MapPath("~/Report/Report_TEST.XLS");
        
                        if (!string.IsNullOrEmpty(filePath ))
                        {
        
        
                            using (MemoryStream ms = new MemoryStream())
                            {
                                using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                                {
                                    byte[] bytes = new byte[file.Length];
                                    file.Read(bytes, 0, (int)file.Length);
                                    ms.Write(bytes, 0, (int)file.Length);
        
                                    HttpResponseMessage httpResponseMessage = new HttpResponseMessage(); 
                                    httpResponseMessage.Content = new ByteArrayContent(ms.GetBuffer());
                                    httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                                    httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        
                                    httpResponseMessage.StatusCode = HttpStatusCode.OK;
                                    return httpResponseMessage;
                                }
                            }
                        }
                        return this.Request.CreateResponse(HttpStatusCode.NotFound, "File not found.");
                    }
                    catch (Exception ex)
                    {
                        return   this.Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
                    }
        
        
                }
        

        这是角度服务:

         protected downloadExcelReportService( reportName: string) {
        
                let completeUrl = this.downloadExcelReportUrl+reportName;
                return Observable.create(observer => {
                    let xhr = new XMLHttpRequest();
        
                    xhr.open('GET', completeUrl, true);
                    xhr.setRequestHeader('Content-type', 'application/json');
                    xhr.responseType='blob';
        
                    xhr.onreadystatechange = function () {
                      if (xhr.readyState === 4) {
                        if (xhr.status === 200) { 
                            debugger;
                          var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
                          var blob = new Blob([xhr.response], { type: contentType });
                          observer.next(blob);
                          observer.complete();
                          return observer;
        
                        } else {
                          observer.error(xhr.response);
                        }
                      }
                    }
                    debugger;
                    xhr.send();
                  });
            }
        

        最后是使用 FileSaver Api 的 Angular 组件方法

        import * as FileSaver from "file-saver";
        
        
        
         downloadexcelReport(data)
              { 
                  this._servive.downloadExcelReport(data.RapproName)
                  .subscribe(
                    _data =>  FileSaver.saveAs(_data, data.RapproName+".xls" ) ), 
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.');  
              }
        

        希望对你有帮助。

        【讨论】:

          【解决方案4】:
          Latest solution Try If using Angular 5:
          
          ///angular side
          
          //header
          let expheaders = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
          let options = new RequestOptions({ headers: expheaders, responseType: ResponseContentType.Blob });
          
          
          this.http.post(this.modeleffectiveperiodserviceurl+"ExportToXlsx",JSON.stringify({
                                     modeleffectiveperioddetails:model,
                                     colheader:columns
                                     }),options)
                                     .subscribe(data => { 
                                       var blob = new Blob([data.blob()], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
                                       var url= window.URL.createObjectURL(blob);
                                       window.open(url);                   
                                    });
          
          
          
          //////////server side
          
          
            byte[] bytes = this._exportmanager.GetExcelFromServer(modeleffectivepc, colheader);
                      HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
                      httpResponseMessage.Content = new ByteArrayContent(bytes.ToArray());
                      httpResponseMessage.Content.Headers.Add("x-filename", fileName);
                      httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                      httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                      httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
                      httpResponseMessage.StatusCode = HttpStatusCode.OK;
                      return httpResponseMessage;
          
          please tell if any problem
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-10-26
            • 1970-01-01
            • 2017-09-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-17
            相关资源
            最近更新 更多