NetCore Vue前端实现导出功能及解决导出excel表格无法打开的问题

本文档描述了在Vue项目中遇到POST接口下载文件无法打开的问题,以及解决方案。问题源于Vue前端调用POST接口下载文件时,由于响应类型设置不当导致文件无法正确打开。解决方案包括:1) 通过解析后台返回的文件流,利用Blob处理数据并创建a标签进行下载;2) 后台封装好文件链接,前端通过链接直接下载。同时,文中提供了相关代码示例和调用方式。

今天做接口导出功能测试,VUE调用接口下载文件总是打不开,使用浏览器或者Postman访问保存文件均正常,接口代码返回如下图:

 后台返回数据:

 VUE前端下载后打开,如图:

 经过一番查找测试之后,因为接口时post的问题,所以传递参数有区别:

1.解析后台返回的文件流

这种方式就是后台将要导出的文件以文件流的方式返回给前端,前端通过blob去解析,再动态创建a标签。

封装单独的导出接口:

xxx.js

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 * * @param {Object} responseType [ 关键,不设置导出的文件无法打开]
 */
export function getBlob(url, params) {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params,
        responseType: "arraybuffer",
      })
      .then((res) => {
        resolve(res);
      })
      .catch((err) => {
        reject(err);
      });
  });
}

要在请求拦截器加上responseType = 'arraybuffer',必须设置,否则导出excel表格打不开,这是get请求,如果Post请求将参数{responseType ='arraybuffer'}加上大括号,否则可能出现打不开的情况,本人项目中封装使用如下:

  

api.js

// 一键导出
export const exportUpload = (names) =>
  getBlob(`/defence/Defence/exportUpload?names=${names}`);

页面通过点击导出:

// 一键导出
    async exportUpload() {
      // window.location = `/defence/Defence/exportUpload?names=${this.queryInfo.names}`;
      // let params = {
      //   names: this.queryInfo.names,
      // };
      // window.open(
      //   `http://172.16.1.120:8080/defence/Defence/exportUpload?names=${this.queryInfo.names}`
      // );
      // window.location.href = `/defence/Defence/exportUpload?names=${this.queryInfo.names}`;
      const res = await exportUpload(this.queryInfo.names);
      console.log(res.data);
      this.resolveBlob(res.data);
    },
    // 处理返回的数据格式
    resolveBlob(res) {
      const link = document.createElement("a");
      link.style.dispaly = "none";
      let binaryData = [];
      binaryData.push(res);
      link.href = window.URL.createObjectURL(new Blob(binaryData));
      // link.href = URL.createObjectURL(res);
      link.setAttribute("download", "装备数据.xlsx");
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    },

2.数据、文件格式全部在后台封装好,返回给前端一个链接,前端通过点击链接自动下载

window.location.href = '/api/xxx/xxx'。
window.open('/api/xxx/xxx?params')。
<a href={`/api/xxx/xxx?params`} download="报表.xlsx">导 出</a>

<think>嗯,用户需要在前端使用HBuilder,后端用C#实现一个导出Excel功能,还要考虑性能和异步处理。首先,我得理清楚前后端的协作流程。前端可能通过发送请求触发导出,后端生成Excel文件,然后返回下载链接或者直接返回文件流。考虑到性能,后端生成Excel的时候要避免内存泄漏,使用高效的库,比如EPPlus或者NPOI。这里选EPPlus吧,因为它在处理Excel方面比较强大,而且支持.NETCore。然后,异步处理是关键,不能让导出操作阻塞其他请求。C#的后端可以用async/await来实现异步方法,这样在生成Excel的时候不会占用线程池线程,提高并发能力。另外,大数据量导出的时候,分页查询数据,避免一次性加载所有数据到内存,这样可以减少内存消耗。 接下来,后端需要设计Controller和Service层。Controller负责接收请求,调用Service生成Excel,然后返回文件。Service里实现具体的导出逻辑,包括查询数据、创建Excel文件、写入数据流。要注意使用Using语句确保资源释放,特别是ExcelPackage对象,避免内存泄漏。 前端方面,HBuilder通常用Vue.js或者uniapp,所以需要用Ajax请求后端的导出接口。考虑到浏览器处理文件下载,后端应该返回文件流,前端可以通过创建Blob对象和a标签触发下载。同时,前端需要处理可能的等待状态,比如显示加载中,防止用户重复点击。 另外,性能优化点:后端可以使用内存流(MemoryStream)来生成Excel,避免临时文件,这样既快又减少IO操作。分批次写入数据,比如每次从数据库取一定数量的记录,写入Excel后再取下一批,这样内存占用更可控。 异常处理也不能忽视,比如数据库查询失败,或者生成Excel时的错误,后端需要捕获异常并返回合适的HTTP状态码,前端相应提示用户导出失败。最后,测试的时候要注意大数据的导出情况,看看内存是否稳定,响应时间是否在可接受范围。可能还需要设置超时时间,防止长时间挂起请求。 现在把这些思路整理成代码,后端Controller用异步Action,Service里分页查询数据,用EPPlus生成Excel到内存流,返回FileResult。前端用axios发送请求,处理响应为文件下载。</think>以下将提供前后端分离的Excel导出方案,重点处理性能优化和异步机制: 🔧后端C#实现(基于.NET Core): ```csharp // Controller层 [ApiController] [Route("api/[controller]")] public class ExportController : ControllerBase { private readonly IExportService _exportService; public ExportController(IExportService exportService) { _exportService = exportService; } [HttpPost("export-excel")] public async Task<IActionResult> ExportExcel([FromBody] ExportRequest request) { // 使用内存流避免临时文件 var stream = new MemoryStream(); // 异步生成Excel await _exportService.GenerateExcelAsync(request, stream); stream.Position = 0; // 返回文件流 return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } } // Service层 public class ExportService : IExportService { private readonly IDbContext _dbContext; public ExportService(IDbContext dbContext) { _dbContext = dbContext; } public async Task GenerateExcelAsync(ExportRequest request, MemoryStream stream) { // 使用分页查询避免内存溢出 const int pageSize = 5000; int pageIndex = 0; using (var package = new ExcelPackage(stream)) { var worksheet = package.Workbook.Worksheets.Add("Data"); // 设置标题行 var headerRow = new List<string[]> { new[] { "ID", "Name", "Value", "CreateTime" } }; worksheet.Cells[1, 1].LoadFromArrays(headerRow); int currentRow = 2; while (true) { // 异步分页查询 var data = await _dbContext.Orders .Where(x => x.CreateTime >= request.StartDate) .OrderBy(x => x.Id) .Skip(pageIndex * pageSize) .Take(pageSize) .Select(x => new object[] { x.Id, x.Name, x.Value, x.CreateTime.ToString("yyyy-MM-dd") }) .ToListAsync(); if (!data.Any()) break; // 批量写入数据 worksheet.Cells[currentRow, 1].LoadFromArrays(data); currentRow += data.Count; pageIndex++; // 及时释放内存 data.Clear(); } await package.SaveAsync(); } } } ``` 🔧前端HBuilder(Vue+axios)实现: ```javascript // 导出方法 async function exportExcel() { try { const loading = uni.showLoading({ title: '生成中...', mask: true }); // 构造请求参数 const params = { startDate: '2023-01-01', endDate: '2023-12-31' }; // 发送异步请求 const response = await axios.post('/api/export/export-excel', params, { responseType: 'blob' }); // 创建下载链接 const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `export_${new Date().getTime()}.xlsx`); document.body.appendChild(link); link.click(); // 清理资源 window.URL.revokeObjectURL(url); document.body.removeChild(link); } catch (error) { uni.showToast({ title: '导出失败', icon: 'none' }); } finally { uni.hideLoading(); } } ``` 💡关键优化点解释: 1. **分页查询**:避免一次性加载全部数据到内存,通过`Skip`/`Take`实现分批次处理 2. **内存流操作**:使用`MemoryStream`代替文件流,减少IO操作 3. **异步编程**:全程使用`async/await`保证线程池高效利用 4. **资源释放**:正确使用`using`语句和及时清理数据集合 5. **响应式流处理**:前端使用blob接收响应,避免大文件内存占用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hefeng_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值