首页 > 解决方案 > 从操作中返回文件并使用 AJAX 下载

问题描述

这可能是重复的,但我还没有找到解决方案。

在我正在开发的应用程序中,有两个export按钮可以将 Excel 文件下载到用户的计算机上。

一个导出按钮执行 POST 表单方法,将参数路由到操作:

<input type="submit" value="EXPORT" id="exportButton" asp-action="ExportResultsData" 
asp-route-ClientID="@listItem.ClientID" asp-route-ProcessingType="@listItem.ProcessingType" 
asp-route-ProgressType="@Model.ProgressType" asp-route-FileName="@listItem.FileName" />

单击时,这些值将路由到控制器操作,它们用于创建文件并将其返回到下载文件的浏览器。都好。

正如我所说,我有另一个按钮需要下载另一个 Excel 文件。但是,这个不同,因为视图模型不包含路由到其控制器操作所需的所有值。每次单击按钮时,我都需要调用一个 JavaScript 函数并获取一个具有以下结构的 JSON 对象:

{
  "draw": 1,
  "columns": [
    {
      "data": "Column1",
      "name": "Column1",
      "searchable": true,
      "orderable": true,
      "search": {
        "value": "",
        "regex": false
      }
    },
    {
      "data": "Column2",
      "name": "Column2",
      "searchable": true,
      "orderable": true,
      "search": {
        "value": "",
        "regex": false
      }
    },
    {
      "data": "Column3",
      "name": "Column3",
      "searchable": true,
      "orderable": true,
      "search": {
        "value": "",
        "regex": false
      }
    },
    {
      "data": "Column4",
      "name": "Column4",
      "searchable": true,
      "orderable": true,
      "search": {
        "value": "",
        "regex": false
      }
    }
  ],
  "order": [
    {
      "column": 0,
      "dir": "asc"
    }
  ],
  "start": 0,
  "length": 15,
  "search": {
    "value": "",
    "regex": false
  },
  "ClientID": 8,
  "FeedbackID": "8",
  "ProcessingType": "Import"
}

每次获取这些参数时,某些值可能会发生变化,并且列数可能会增加/减少。

我可以到达控制器操作,将参数绑定到模型,并成功生成 Excel 文件,但文件没有下载,只是返回到 AJAXsuccess部分:

function ExportFeedbackData(clientID, feedbackID, processingType) {
    var jqueryParams = GetJqueryParams();
    $.ajax({
        url: '/Client/ExportFeedbackData',
        type: 'POST',
        data: {
            DatatablesParameters: jqueryParams,
            ClientID: clientID,
            FeedbackID: feedbackID,
            ProcessingType: processingType,
        },
        success: function (exportedFile) {
            console.log(exportedFile);
            //file data just returns here and doesn't download
        },
        error: function (errormsg) {
            console.log(errormsg);
        }
    });
}

控制器动作:

//"DatatablesParameters" refers to parameters sent from a JS plugin called Datatables https://datatables.net/
//https://datatables.net/manual/server-side
public IActionResult ExporFeedbackData(DataTablesParameters DatatablesParameters, int ClientID, int FeedbackID, string ProcessingType)
{
    DataTable dt = _processingService.ReturnDataTable(DatatablesParameters, ClientID, FeedbackID, ProcessingType);

    using (ExcelPackage package = new ExcelPackage())
    {
        ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(ProcessingType);
        worksheet.Cells["A1"].LoadFromDataTable(dt, PrintHeaders: true);
        for (var i = 0; i < dt.Columns.Count; i++)
        {
            worksheet.Cells.AutoFitColumns();
        }
        return File(package.GetAsByteArray(), XlsxContentType, $"{ProcessingType}.xlsx"); //Excel file returned
    }
}

所以,我想要的是能够用 AJAX 下载文件,但我不知道该怎么做。该文件也可能很大。我也很想以某种方式消除 AJAX 并动态生成<input>标签,但每次我导出 jquery 对象中的值可能会有所不同。我也对其他解决方案持开放态度。

我主要担心清洁度和可靠性。通过表单提交,您只需单击按钮即可下载。但是对于 AJAX,它看起来更加混乱。

标签: javascriptajaxasp.net-mvcasp.net-coredownload

解决方案


AJAX 请求是一个瘦客户端请求。响应不会自动发生任何事情;程序员需要对响应执行任何操作。由于要提示文件下载,因此需要在 href 中动态创建一个将文件数据作为对象 URL 的锚链接,然后“单击”它。

let a = document.createElement('a');
let url = window.URL.createObjectURL(exportedFile);
a.href = url;
a.download = 'myfile.xlsx';
document.body.append(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);

推荐阅读