React浏览器下载经C# Aspose Cells处理的Excel文件损坏求助
React下载Excel文件损坏问题解决
问题场景
通过React调用C# API处理Excel文件:API接收文件后用Aspose Cells修改,将修改后的文件转为Byte[]返回前端;前端将Byte[]转为Blob触发下载,但打开文件时提示损坏。
原代码
服务端C# API代码
public async Task<Byte[]> ExportToExcel(IFormFile file) { if (file == null || file.Length == 0) { return null; } try { using (var stream = file.OpenReadStream()) { Workbook workbook = new Workbook(stream); var worksheet = workbook.Worksheets[0]; Cells cells = worksheet.Cells; FindOptions findOptions = new FindOptions(); findOptions.CaseSensitive = false; findOptions.LookInType = LookInType.Values; findOptions.LookAtType = LookAtType.Contains; // Doing modifications in Excel file.... // Save the modified workbook as Excel file var excelMemoryStream = new MemoryStream(); workbook.Save(excelMemoryStream, SaveFormat.Xlsx); byte[] data = excelMemoryStream.ToArray(); return data; } } catch (Exception ex) { throw; } }
客户端React代码
const onBtExport = () => { const csvData = gridRef.current.api.getDataAsExcel(); console.log(csvData); instance .acquireTokenSilent({ ...accessToken, account: accounts[0], }) .then(async (response) => { const formData = new FormData(); formData.append('file', csvData); ExportToExcel(response.accessToken, formData).then((res) => { if (res.data.Status === true) { console.log(res.data.Data); const blob = new Blob([res.data.Data],{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) console.log(blob); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'ContractSummaryReport.xlsx'; a.click(); URL.revokeObjectURL(a.href); } else { toast.error(res.data.Message); } }); }); };
问题根源
- 服务端:返回
Byte[]时,ASP.NET会自动将其序列化为JSON数组(如[255,216,255,...]),而非原始二进制流,前端拿到的是数字数组而非有效文件数据。 - 客户端:未设置正确的
responseType,Axios默认将响应解析为JSON,导致二进制数据被错误转换;同时直接将JSON化的数字数组转为Blob,无法还原有效Excel文件。
修正方案
服务端代码修改
将返回类型改为FileStreamResult,直接输出二进制流并指定正确MIME类型:
public async Task<IActionResult> ExportToExcel(IFormFile file) { if (file == null || file.Length == 0) { return BadRequest("上传文件为空"); } try { using (var stream = file.OpenReadStream()) { Workbook workbook = new Workbook(stream); var worksheet = workbook.Worksheets[0]; Cells cells = worksheet.Cells; FindOptions findOptions = new FindOptions(); findOptions.CaseSensitive = false; findOptions.LookInType = LookInType.Values; findOptions.LookAtType = LookAtType.Contains; // 执行Excel修改操作... var excelMemoryStream = new MemoryStream(); workbook.Save(excelMemoryStream, SaveFormat.Xlsx); excelMemoryStream.Position = 0; // 重置流指针到起始位置 // 返回二进制文件流 return File( excelMemoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ContractSummaryReport.xlsx" ); } } catch (Exception ex) { return StatusCode(500, "文件处理失败:" + ex.Message); } }
客户端代码修改
- 设置Axios请求的
responseType: 'arraybuffer',确保接收原始二进制数据。 - 简化响应处理,直接用返回的二进制数据创建Blob。
const onBtExport = () => { const excelBlob = gridRef.current.api.getDataAsExcel(); instance .acquireTokenSilent({ ...accessToken, account: accounts[0], }) .then(async (response) => { const formData = new FormData(); formData.append('file', excelBlob); // 调用API时指定responseType ExportToExcel(response.accessToken, formData) .then((res) => { const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'ContractSummaryReport.xlsx'; a.click(); URL.revokeObjectURL(a.href); }) .catch(() => { toast.error('文件下载失败,请重试'); }); }); }; // 封装的ExportToExcel请求,添加responseType配置 const ExportToExcel = (token, formData) => { return axios.post('/api/ExportToExcel', formData, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'multipart/form-data' }, responseType: 'arraybuffer' // 关键配置,确保接收二进制数据 }); };
关键说明
- 服务端返回
FileStreamResult能避免JSON序列化导致的二进制数据失真,同时自动设置正确的响应头。 - 客户端必须设置
responseType: 'arraybuffer',否则Axios会将二进制数据解析为UTF-8字符串,导致Blob损坏。 - ag-Grid的
getDataAsExcel()返回的是Blob对象,直接添加到FormData即可,无需额外转换。
内容的提问来源于stack exchange,提问作者Suprateem Bose
相关产品推荐
相关产品推荐

