JavaScript: Еще один вариант загрузки файла по клику на кнопку
Общая идея следующая: по клику на кнопку вызываем AJAX запрос на сервер с определенными параметрами передаваемыми в POST, затем получив в результат запроса файл — формируем в DOM на файл в формате blob, и тут-же её нажимаем. В результате браузер показывает диалоговое окно сохранения файла.
Таким необычным способом мы убиваем несколько зайцев сразу:
- Получаем возможность показать ошибку, если вдруг файл на сервере сформировать не удалось. Это полезно если например файл формируется на сервере «на лету» — например файл XLSX с отчётом
- Мы можем передать серверу какие-то условия для формирования файла в POST запросе
- На странице мы не размещаем заранее данные в тегах <form></form>, как практикуется в подобных решениях
- Пользователю достаточно нажать на кнопку один раз для получения результата.
В результате скрипт формирования файла может выглядеть примерно следующим образом:
На клиенте:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/** * Формирование отчета * @param {type} filename - имя файла на сервере для формирования отчета * @param {type} ext - выходное расширение (например xlsx,csv) * @returns {Number} */ function get_report(filename,ext){ $("#global").addClass("loading"); var xhr = new XMLHttpRequest(); xhr.open('POST', '?r=reports/'+filename, true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.responseType = 'blob'; xhr.onload = function(e) { $("#global").removeClass("loading"); if (this.status == 200) { var link=document.createElement('a'); link.href=window.URL.createObjectURL(this.response); console.log("Расширение:"+ext); link.download="report."+ext; link.click(); } else { console.log(e); ToastMessage("error","Произошла ошибка при формировании файла. Попробуйте позднее или обратитесь к администратору системы."); } }; var form_data = new Map(); form_data.period_from = period_from.value; form_data.period_to = period_to.value; form_data.area = area_select.value; form_data.division_check=division_check.checked; form_data.period_check=period_check.checked; xhr.send(mapToQueryString(form_data)); }; |
На сервере:
1 2 3 4 5 6 7 8 9 10 11 12 |
public function actionGet_report_by_settlers(){ $request = Yii::$app->request; $area= $request->post("area"); $dir=Yii::$app->basePath."/web/templates"; $oSpreadsheet = IOFactory::load($dir . "/report_1_1.xlsx"); ... формируем файл эксель ... $oWriter = IOFactory::createWriter($oSpreadsheet, 'Xlsx'); $oWriter->save('php://output'); }; |