Angular2从Web API下载excel文件,文件已损坏 [英] Angular2 download excel file from Web API, file is corrupt
问题描述
我正在尝试下载使用ClosedXML创建的文件.我已经验证文件没有损坏,但是由于某种原因,它仅适用于Angular1,而不适用于Angular2.返回文件的Web api代码为:
I am trying to download a file that I created with ClosedXML. I have verified that the file is not corrupt but, for some reason, it works just with Angular1, not Angular2. The web api code to return the file is:
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中,在我的Web服务中:
In Angular2, in my web service:
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下载时文件大小是文件的两倍.
A file IS downloaded, but it is corrupt when I try to access it and is TWICE the size of the file when downloaded with Angular1.
如果我使用Angular1调用SAME API,则文件下载正常.
If I call the SAME API with Angular1, the file is downloaded fine.
我的服务代码:
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上找到它)
where handleSuccess returns response.data (which I can't get at for angular2)
以及调用该服务的代码:
and the code to invoke the service:
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,但只是想尝试一下),然后摆脱了服务代码并简单地进行了此调用,该文件就可以了:
Interestingly enough, in Angular2, if I simply change my webservice to a GET (I wanted POST however, but just to try it out) then got rid of the service code and simply made this call, the file is fine:
window.open(`${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, "_blank");
那么,真的,这里有什么区别?为什么相同或非常相似的代码可用于Angular1而不适用于Angular2?
So, really, what is the difference here? Why does the same or very similar code work for Angular1 but not Angular2??
-凯伦(Karen)
推荐答案
我知道其他人也发现了同样的问题.我已经解决了,但是不得不切换到xhr使其起作用.
I know that others have found the same problem. I have resolved it, but had to switch to xhr to make it work.
第一种方法无效.我从上面做了一些简化:
This first method is the one that does NOT work. I simplified it somewhat from above:
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);
}
这第二种方法确实可行:
This second method is the one that DOES work:
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();
});
}
希望这对其他人有帮助!我看到此问题在其他地方发布,因此我也将在其中添加指向我的解决方案的链接.
Hopefully this will help others! I saw this issue posted elsewhere so I will add a link to my solution there as well.
-凯伦(Karen)
这篇关于Angular2从Web API下载excel文件,文件已损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!