我在Angular 2和Typescript上有一个简单的服务,该服务向服务器请求Excel文件,然后为用户打开下载文件对话框。但是,目前,该文件在下载时已损坏。
下载后,它在OpenOffice中可以很好地打开并进行衍生,但是在Microsoft Excel上引发“文件已损坏”错误,并询问用户是否要尽可能地恢复。
当提示Excel恢复文件时,它成功完成了此操作,并且恢复的Excel具有Excel文件所需的所有行和数据。将恢复的文件与在OpenOffice中打开文件进行比较,得出没有明显差异的证据。
我要下载的具体Excel是通过微服务中的Apache POI生成的,然后传递到主要后端,最后提供给前端供用户下载。后端和微服务都是通过Spark Framework用Java编写的。
我在后端进行了一些测试,并得出结论,问题不在于报告生成还是数据传输:
要求微服务将生成的Excel保存到服务器内的文件中,然后在Excel中打开该文件(此处为文件A)显示文件未损坏。
要求主后端服务器将其从微服务接收到的Excel文件保存在其自身的文件中,然后在Excel中打开该文件(据此称为文件B)表明文件B不是 已损坏。
通过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");
});
}
以下是我正在使用的工具的版本:
在此问题上的任何帮助将不胜感激。您可能需要我提供的其他任何信息。
答案 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