Laravel+Maatwebsite中Ajax响应无法自动触发Excel下载问题
问题场景

实现复选框勾选批量导出Excel功能时,使用Ajax发起请求可以正常获取后端返回数据,但无法自动触发Excel文件下载,手动在新标签页打开对应请求URL可正常下载文件。
现有前端代码
$(document).on('click', '#selectAll', function() { $(".order").prop("checked", this.checked); var total = $("input.order:checked").length + " Orders Selected"; $('#selected').html(total); }); $(document).on('click', '.order', function() { if ($('.order:checked').length == $('.order').length) { $('#selectAll').prop('checked', true); } else { $('#selectAll').prop('checked', false); } var total_single = $("input.order:checked").length + " Orders Selected"; $('#selected').html(total_single); }); $(document).ready(function() { $('#export_records').on('click', function(e) { e.preventDefault(); var orders = []; $(".order:checked").each(function(){ orders.push($(this).val()); }); if (orders.length <= 0) { alert("Please select records."); } else { var selected_values = orders; $.ajax({ type: "GET", url: "{{route('mfiint_export_bulk')}}", cache: false, data: {'orders':selected_values,"_token":"{{ csrf_token() }}"}, success:function(data){ // 此处编写的自动下载逻辑无法生效 } }); } }); });
现有后端代码
控制器导出响应逻辑:
return Excel::download(new mfiintBulkExport($purchases_bulk),'bulkorders.xlsx');
导出类实现代码:
public function __construct($purchases_bulk) { $this->purchases_bulk = $purchases_bulk; } public function view(): View { return view('mfiint.bulk_orderexport',['purchases_bulk'=>$this->purchases_bulk]); }
问题原因
普通Ajax请求接收的是二进制文件流,浏览器不会自动识别这类响应触发默认下载行为。在success回调中直接处理二进制流的方案兼容性差、实现冗余,文件下载场景本身就不适合用普通Ajax发起请求。
解决方案
推荐方案:动态构造表单提交(兼容性最好)
不需要走Ajax请求,动态创建隐藏表单提交参数,浏览器会自动识别文件响应触发下载,兼容所有主流浏览器,代码简洁稳定。
替换原有Ajax部分的逻辑即可:
$('#export_records').on('click', function(e) { e.preventDefault(); var orders = []; $(".order:checked").each(function(){ orders.push($(this).val()); }); if (orders.length <= 0) { alert("Please select records."); return false; } // 动态创建提交表单 var downloadForm = $('<form action="{{route('mfiint_export_bulk')}}" method="GET" target="_blank"></form>'); // 加入CSRF校验参数 downloadForm.append('<input type="hidden" name="_token" value="{{ csrf_token() }}">'); // 加入所有选中的订单ID orders.forEach(function(orderId){ downloadForm.append('<input type="hidden" name="orders[]" value="'+orderId+'">'); }); // 临时挂载表单触发提交,提交完成后移除表单 downloadForm.appendTo('body').submit().remove(); });
备选方案:Ajax+Blob实现(需指定响应类型)
如果必须使用Ajax实现,需要在请求配置中声明响应类型为二进制Blob,拿到响应后创建临时a标签触发下载:
$.ajax({ type: "GET", url: "{{route('mfiint_export_bulk')}}", cache: false, // 必须指定响应类型为blob xhrFields: { responseType: 'blob' }, data: {'orders':selected_values,"_token":"{{ csrf_token() }}"}, success:function(blobData){ // 生成Blob临时地址 var blobUrl = window.URL.createObjectURL(blobData); // 创建临时a标签触发下载 var tempLink = document.createElement('a'); tempLink.href = blobUrl; tempLink.download = 'bulkorders.xlsx'; document.body.appendChild(tempLink); tempLink.click(); // 释放资源,移除临时元素 document.body.removeChild(tempLink); window.URL.revokeObjectURL(blobUrl); } });
注意:Blob方案在部分低版本浏览器存在兼容问题,无特殊需求优先选择动态表单方案。
内容的提问来源于stack exchange,提问作者Mannu254
相关产品推荐
相关产品推荐

