【问题标题】:Axios Excel file download using POST results in corrupted file使用 POST 下载 Axios Excel 文件会导致文件损坏
【发布时间】: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));
    }

我不确定问题出在responseTypeheaders,还是响应的处理方式或以上所有问题。到目前为止,我已经尝试了各种选择,但都没有运气。任何建议将不胜感激!

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

【问题讨论】:

    标签: excel reactjs axios


    【解决方案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)
              }
            });
          });
      };
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-15
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 2013-07-12
      • 2017-09-13
      相关资源
      最近更新 更多