我正在尝试下载使用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,但只是尝试一下)然后摆脱服务代码并简单地进行此调用,文件很好:< / p>
window.open(`${AppSettings.REPORTS_API_URL}/Report/MonthlySpreadsheet`, "_blank");
所以,真的,这有什么区别?为什么相同或非常相似的代码适用于Angular1但不适用于Angular2 ??
- 凯伦
答案 0 :(得分:3)
我知道其他人也发现了同样的问题。我已经解决了,但必须切换到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();
});
}
希望这会对别人有所帮助!我在其他地方看到了这个问题,所以我也会在那里添加一个链接到我的解决方案。
- 凯伦
答案 1 :(得分:1)
这对我有用(确保服务确实将xlsx文件作为响应发回):
为show“save file”弹出窗口
安装这些依赖项npm install file-saver --save-dev
npm install @types/file-saver --save-dev
导入您的服务:
import * as FileSaver from 'file-saver';
用法:
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);
});
}
答案 2 :(得分:1)
这是我用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.');
}
我希望能帮助你。
答案 3 :(得分:0)
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