使用 POST 下载 Axios Excel 文件导致文件损坏

IT技术 excel reactjs axios
2021-04-17 19:04:38

我以前使用 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));
    }

我不知道,如果问题出在responseTypeheaders或如何响应的处理或全部的上方。到目前为止,我已经尝试了各种选择,但都没有运气。任何建议将不胜感激!

我已经能够使用 Postman 下载文件,所以我知道端点提供的文件很好。我只是无法在我的 React 代码中整理出执行此操作的参数。

2个回答

终于让它工作了!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 对象将保留在内存中,直到文档卸载(用户关闭选项卡!)。
2021-06-13 19:04:38

我们可以使用以下代码从 POST 方法中导出 Excel 文件。愿它帮助某人并节省时间。

API 使用 .Net Core 2.2,方法如下。

注意:当我们创建 FileStreamResult 时,响应的 Content-Disposition 标头将包含文件名,流将作为附件出现。

在启动文件中将“Content-Disposition”添加到 Cors,

 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;
            }

Action方法代码如下

[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**
      }
    );
  };

操作方法代码如下。这里我使用“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)
          }
        });
      });
  };
};