下载Excel文件会导致其损坏

时间:2018-10-26 21:44:28

标签: angularjs typescript filesaver.js

我在Angular 2和Typescript上有一个简单的服务,该服务向服务器请求Excel文件,然后为用户打开下载文件对话框。但是,目前,该文件在下载时已损坏。

下载后,它在OpenOffice中可以很好地打开并进行衍生,但是在Microsoft Excel上引发“文件已损坏”错误,并询问用户是否要尽可能地恢复。

当提示Excel恢复文件时,它成功完成了此操作,并且恢复的Excel具有Excel文件所需的所有行和数据。将恢复的文件与在OpenOffice中打开文件进行比较,得出没有明显差异的证据。

我要下载的具体Excel是通过微服务中的Apache POI生成的,然后传递到主要后端,最后提供给前端供用户下载。后端和微服务都是通过Spark Framework用Java编写的。

我在后端进行了一些测试,并得出结论,问题不在于报告生成还是数据传输:

  1. 要求微服务将生成的Excel保存到服务器内的文件中,然后在Excel中打开该文件(此处为文件A)显示文件损坏。

  2. 要求主后端服务器将其从微服务接收到的Excel文件保存在其自身的文件中,然后在Excel中打开该文件(据此称为文件B)表明文件B不是 已损坏。

  3. 通过FileZilla从其各自的服务器下载文件A和文件B会产生完全未损坏的文件。

这样,我认为可以肯定地认为,在前端接收到文件到用户下载该文件之间,Excel在某个地方已损坏。此外,Catalina日志不能证明可能会发生的任何错误。

我已经阅读了几篇有关此问题的文章,包括一个错误报告(https://github.com/angular/angular/issues/14083),其中包括通过XMLHTTPRequest的解决方法。但是,没有详细说明的解决方法能够成功解决我的问题。

随附的代码是我用来从后端获取Excel文件并将其提供给用户的代码。我同时包含了XMLHTTPRequest和Angular http调用(在注释中),因为这是我一直试图使其工作的两种主要方法。此外,请务必考虑代码已被更改以删除我不想公开的信息。

download(body) {
    let reply = Observable.create(observer => {
      let xhr = new XMLHttpRequest();

      xhr.open('POST', 'URL', true);
      xhr.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
      xhr.setRequestHeader('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
      xhr.setRequestHeader('Authorization', 'REDACTED');

      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(JSON.stringify(body));
    });

    return reply;


    /*let headers = new Headers();
    headers.set("Authorization", 'REDACTED');
    headers.set("Accept", 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

    let requestOptions :RequestOptions = new RequestOptions({headers: headers, responseType: ResponseContentType.Blob});

    return this.http.post('URL', body, requestOptions);*/
  }

此处是提示用户下载Excel的代码。目前,它可以与XMLHTTPRequest一起使用。请注意,我也尝试过不借助FileSaver进行下载,但是没有运气。

downloadExcel(data) {
    let body = {
      /*REDACTED*/
    }

    this.service.download(body)
        .subscribe(data => {
          FileSaver.saveAs(data, "Excel.xlsx");
        });
  }

以下是我正在使用的工具的版本:

  • NPM:5.6.0
  • NodeJ:8.11.3
  • 角度JS:^ 6.1.0
  • 使用的浏览器:Chrome,Firefox,Edge。

在此问题上的任何帮助将不胜感激。您可能需要我提供的其他任何信息。

2 个答案:

答案 0 :(得分:0)

我认为您想要的是在Excel中打开的CSV格式,请如下更新您的服务:

您应该告诉Angular,您期望的Excel / Csv文件类型为blob(二进制大对象)。

还要确保服务器上的URL / API设置为接受content-type='text/csv'

这是Angular 2的示例。

@Injectable()
export class YourService {

    constructor(private http: Http) {}

    download() { //get file from the server
        this.http.get("http://localhost/..", {
            responseType: ResponseContentType.Blob,
            headers: new Headers({'Content-Type', 'text/csv'})
        }).subscribe(
            response => {
                var blob = new Blob([response.blob()], {type: 'text/csv'});
                FileSaver.saveAs(blob, 'yourFileName.csv');
            },
            error => {
                console.error('something went wrong');
            }
        );
    }
}

答案 1 :(得分:0)

您是否尝试过将xls文件作为base64上传/下载?

var encodedXLSToUpload = 'data:application/xls;base64,' + btoa(file);

请检查此以获取更多详细信息:Creating a Blob from a base64 string in JavaScript