使用 POST 下载 Axios Excel 文件会导致文件损坏
Posted
技术标签:
【中文标题】使用 POST 下载 Axios Excel 文件会导致文件损坏【英文标题】:Axios Excel file download using POST results in corrupted file 【发布时间】:2019-11-29 07:52:29 【问题描述】:我之前使用 Axios 下载 GET 端点提供的文件。端点已更改,现在是 POST,但不需要参数。我正在更新原始下载方法,但返回的文件已损坏。
downloadTemplate()
axios.post(DOWNLOAD_TEMPLATE_URL,
responseType: 'blob',
headers:
'Content-Disposition': "attachment; filename=template.xlsx",
'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
)
.then((response) =>
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'template.xlsx');
document.body.appendChild(link);
link.click();
)
.catch((error) => console.log(error));
我不确定问题出在responseType
、headers
,还是响应的处理方式或以上所有问题。到目前为止,我已经尝试了各种选择,但都没有运气。任何建议将不胜感激!
我已经能够使用 Postman 下载文件,因此我知道端点提供的文件很好。我只是无法在我的 React 代码中整理出执行此操作的参数。
【问题讨论】:
【参考方案1】:终于搞定了!问题代码块中的post
语法不正确,还将responseType
更改为“arraybuffer”。
下面的工作示例:
downloadTemplate()
axios.post(DOWNLOAD_TEMPLATE_URL, null,
headers:
'Content-Disposition': "attachment; filename=template.xlsx",
'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,
responseType: 'arraybuffer',
).then((response) =>
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'template.xlsx');
document.body.appendChild(link);
link.click();
)
.catch((error) => console.log(error));
【讨论】:
强烈建议您在单击链接后调用revokeObjectURL(url)
,否则blob对象将保留在内存中直到文档卸载(用户关闭选项卡!)。【参考方案2】:
我们可以使用以下代码从 POST 方法中导出 Excel 文件。希望它可以帮助某人并节省时间。
API使用.Net Core 2.2,方法如下。
注意:当我们创建 FileStreamResult 时,响应的 Content-Disposition 标头将包含文件名,并且流将作为附件出现。
在 Cors at Startup 文件中添加“Content-Disposition”,
app.UseCors(b => b.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials().WithExposedHeaders("Content-Disposition"));
我正在使用EPplus 包来生成 Excel 文件。
using OfficeOpenXml;
using OfficeOpenXml.Style;
public static MemoryStream InvoiceToExcel(List<InvoiceSearchDto> invoices)
var listOfFieldNames = typeof(InvoiceSearchDto).GetProperties().Select(f => f.Name).ToList();
int cellCounter = 1, recordIndex = 2;
var ms = new MemoryStream();
using (ExcelPackage package = new ExcelPackage(ms))
ExcelWorksheet worksheet;
worksheet = package.Workbook.Worksheets.Add("New HGS");
// Setting the properties of the first row
worksheet.Row(1).Height = 20;
worksheet.Row(1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
worksheet.Row(1).Style.Font.Bold = true;
// Header of the Excel sheet
foreach (string header in listOfFieldNames)
worksheet.Cells[1, cellCounter++].Value = header;
// Inserting the article data into excel
// sheet by using the for each loop
// As we have values to the first row
// we will start with second row
foreach (InvoiceSearchDto invoice in invoices)
worksheet.Cells[recordIndex, 1].Value = invoice.CompanyName;
worksheet.Cells[recordIndex, 2].Value = invoice.CustomerNo;
worksheet.Cells[recordIndex, 3].Value = invoice.DocumentNumber;
worksheet.Cells[recordIndex, 4].Value = invoice.BillingPeriodStartDate.ToString("YYYY-MM-DD");
worksheet.Cells[recordIndex, 5].Value = invoice.BillingPeriodEndDate.ToString("YYYY-MM-DD");
worksheet.Cells[recordIndex, 6].Value = invoice.DateOfInvoice.ToString("YYYY-MM-DD");
worksheet.Cells[recordIndex, 7].Value = invoice.ExpirationDate.ToString("YYYY-MM-DD");
worksheet.Cells[recordIndex, 8].Value = invoice.Amount;
worksheet.Cells[recordIndex, 9].Value = invoice.InvoiceStatusText;
recordIndex++;
// By default, the column width is not
// set to auto fit for the content
// of the range, so we are using
// AutoFit() method here.
worksheet.Column(1).AutoFit();
worksheet.Column(2).AutoFit();
worksheet.Column(3).AutoFit();
worksheet.Column(4).AutoFit();
worksheet.Column(5).AutoFit();
worksheet.Column(6).AutoFit();
worksheet.Column(7).AutoFit();
worksheet.Column(8).AutoFit();
worksheet.Column(9).AutoFit();
package.Save();
ms.Position = 0;
return ms;
动作方法代码如下
[HttpPost]
[Route("[action]")]
public IActionResult GetInvoiceWithExcel([FromBody]SearchInvoice searchInvoice)
try
if (!string.IsNullOrEmpty(searchInvoice.InvoiceDateFrom))
searchInvoice.DateFrom = Convert.ToDateTime(searchInvoice.InvoiceDateFrom);
if (!string.IsNullOrEmpty(searchInvoice.InvoiceDateTo))
searchInvoice.DateTo = Convert.ToDateTime(searchInvoice.InvoiceDateTo);
var invoices = invoiceBatchService.GetAllForExcel(searchInvoice.PagingParams, searchInvoice, searchInvoice.FilterObject);
if (invoices != null)
MemoryStream invoiceStream = ExcelConverter.InvoiceToExcel(invoices);
var contentType = "application/octet-stream";
var fileName = "Invoice.xlsx";
return File(invoiceStream, contentType, fileName);
else
ResponseModel.Notification = Utility.CreateNotification("Not Found Anything", Enums.NotificationType.Warning);
return NotFound(ResponseModel);
catch (Exception ex)
NLogger.LogError(ex, "Get Invoice With Excel");
ResponseModel.Notification = Utility.CreateNotification(Helpers.ExceptionMessage(ex), Enums.NotificationType.Error);
return StatusCode(500, ResponseModel);
最后的 React 和 axois 代码如下。
服务代码:
return http.post(
API_BASE_URL + "/Invoice/GetInvoiceWithExcel",
searchInvoice,
headers: getHeaders(), // for token and others
responseType: 'blob' // **don't forget to add this**
);
;
Action 方法代码如下。这里我使用"file-saver"包下载文件。
import saveAs from 'file-saver';
export const getInvoiceWithExcel = invoiceInfo =>
return dispatch =>
dispatch(
type: LOADING_ON
);
InvoiceService.getInvoiceWithExcel(invoiceInfo)
.then(res =>
console.log(res);
let filename = res.headers['content-disposition']
.split(';')
.find((n) => n.includes('filename='))
.replace('filename=', '')
.trim();
let url = window.URL
.createObjectURL(new Blob([res.data]));
saveAs(url, filename);
dispatch(
type: GET_INVOICE_EXCEL_SUCCESS,
payload: ""
);
dispatch(
type: LOADING_OFF
);
dispatch(
type: ON_NOTIFY,
payload:
...res.data.notification
);
)
.catch(err =>
dispatch(
type: GET_INVOICE_EXCEL_FAILED
);
dispatch(
type: LOADING_OFF
);
dispatch(
type: ON_NOTIFY,
payload:
...Utility.errorResponseProcess(err.response)
);
);
;
;
【讨论】:
以上是关于使用 POST 下载 Axios Excel 文件会导致文件损坏的主要内容,如果未能解决你的问题,请参考以下文章