前端需设置 responseType: 'blob'(fetch 用 res.blob(),jQuery 用 xhrFields: {responseType: 'blob'}),再通过 URL.createObjectURL 创建临时链接并触发 a 标签下载,同时复用列表筛选参数、避免分页参数,确保权限校验一致,并防范大文件内存溢出与响应体污染。
后端导出接口返回的是文件流,前端怎么触发下载
直接用 fetch 或 $.ajax 请求后端导出接口,拿到的响应体是 blob,不是 json。如果误当 json 解析(比如写 res.json()),会报错或卡死。
正确做法是:禁用自动解析,显式设置 responseType: 'blob',再用 URL.createObjectURL 创建临时链接下载。
- 使用
fetch时加{method: 'POST', responseType: 'blob'}(注意 Fetch 没有原生responseType,得用res.blob()) - 用
jQuery.ajax更直观:dataType: 'binary', xhrFields: {responseType: 'blob'} - 下载前加
layer.load(),防止用户重复点击;下载完成后手动layer.close() - 文件名不能从响应头
Content-Disposition自动读取(IE 不支持),建议后端在 JSON body 里额外返回filename字段,或前端拼接固定名
导出请求要带筛选参数,但 table 是后端分页,怎么传?
表格当前页的搜索条件(如日期范围、状态)存在 table.getCheckData() 拿不到,它只返回勾选行;真正要用的是你当初调用 table.render() 时传的 where 参数,或表单 form.val('filterForm') 的值。
常见错误:把 page=1&limit=10 直接发给导出接口——这只会导出第一页数据,不是全量。
- 导出请求必须复用和列表接口**完全一致的筛选参数**,但去掉
page和limit - 如果筛选逻辑复杂(比如时间范围转为 SQL BETWEEN),别在前端拼,让后端统一处理
- 接口路径建议和列表接口分离,例如列表用
/api/user/list,导出用/api/user/export,避免歧义
大文件(>50MB)下载失败或中断怎么办
浏览器对 Blob URL 有内存限制,Chrome 通常卡在 500MB 左右;IE 更低。一旦 new Blob([res]) 报 RangeError: Invalid array length,说明响应体太大,前端已扛不住。
这不是代码问题,是架构问题:前端不该承担大文件组装和内存缓冲。
- 后端应改用流式响应(
Transfer-Encoding: chunked),并设置Content-Transfer-Encoding: binary - 更稳妥方案是后端生成文件后返回一个临时下载地址(如
/download/abc123.xlsx),前端跳转或window.open(),绕过 Blob 内存瓶颈 - 若必须走 AJAX + Blob,需加超时兜底:
timeout: 300000(5 分钟),并提示“导出耗时较长,请勿关闭页面”
导出完成但 Excel 打开提示“发现不可读内容”,怎么定位
90% 是后端返回了非纯二进制流——比如日志打到了响应体里、异常堆栈混在文件开头、或者 JSON 错误响应被当成了文件流。
最简单验证方式:用浏览器直接访问导出接口 URL(GET 方式),看是否弹出下载框;如果弹出但文件打不开,就用 curl -v 或 Fiddler 抓包,检查响应头 Content-Type 是否为 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,且响应体开头是 PK\x03\x04(ZIP 签名,.xlsx 必须有)。
- 后端框架(如 Spring Boot)容易因全局异常处理器把 500 响应也写成 JSON,导致导出接口返回
{"code":500,"msg":"xxx"}却设了 Excel 的 Content-Type - Node.js 中用
res.sendFile()前,务必先res.setHeader('Content-Type', '...'),否则 MIME 类型可能被自动推断为text/plain - 前端不要对响应做任何字符串处理(如
res.text().then(x => new Blob([x]))),必须用res.blob()
















