Безопасность превыше всего! Именно поэтому постоянно приходится тратить время и творческую энергию на придумывание способов обхода ограничений безопасности в браузерах. В частности, AJAX. Инструмент был бы реально универсальным и многоцелевым, если бы не его функциональность не была искусственно ограничена по требованиям безопасности. Ну а поскольку альтернатив практически нет, постоянно приходится искать обходные пути.
Ну ладно, операции с куки через AJAX мы реализовали, передачу файлов на сервер сделали при помощи API FormData, де-факто ставшего стандартом во всех браузерах, теперь пора подумать о противоположной задаче - загрузка файлов с сервера. Речь не идет о статичных файлах - там можно тупо передать ссылку на файл.
Часто встречающаяся у бухов задача: передать на сервер (методом POST) некие данные, на основе которой сервер выполнит выборку из БД, оформит результат в виде таблицы MS Excel и вернет в браузер файл XLS. Выглядеть и работать это должно как можно проще: юзверь кликает по ссылке или кнопке, и у него открывается системное диалоговое окно для сохранения полученного файла на диск.
Вообще, очевидное решение напрашивается само собой: серверный скрипт создает таблицу, сохраняет ее в файл на сервере, потом передает клиенту ссылку на этот файл. Но мы не будем искать простых путей и не хотим использовать костыли в виде промежуточных файлов. К тому же такое решение требует решения дополнительных задач в виде прав на чтение-запись на сервере и уникальных имен файлов, что не всегда удобно. Почему бы не выводить созданный файл непосредственно в STDOUT?
Практически сразу выяснилось, что реализовать это через AJAX не получится от слова совсем. Аякс тупо не воспринимает HTTP хедеры типа force-download (в целях безопасности, ага), а попытки как-то обойти это быстро обросли таким лесом капризных и весьма ненадежных костылей, что от этой идеи пришлось отказаться.
Поэтому мы пойдем другим путем. А именно - создание псевдо-формы и отправка ее на сервер обычным браузерным POST-запросом. Ну а асинхронность при желании можно добиться при помощи промисов. Как ни странно, иногда простые решения оказываются лучше, и такой финт ушами заработал именно так, как требуется.
Итак, функция на жабаскрипте, принимающая в качестве аргументов имя формы и ссылку на серверный скрипт, причем вместе с GET-аргументами. Она создает клон формы, добавляет в нее новые поля (например, данные об авторизации юзверя) и отправляет методом POST, после чего ответ передается непосредственно в браузер, а сделавший свое дело клон убивается.
Ну и скрипт на сервере, создающий XLS на основе полученных данных, присоединяющий к нему правильный хедер и возвращающий непосредственно в HTTP, без промежуточного сохранения на диск:Код:function loadFile(name, url) { var nod = document.getElementById('tempdiv'); var myform = document.forms[name].cloneNode(true); myform.action = url; myform.name = "cloneForm"; myform.method = "post"; var inp = document.createElement("input"); inp.name = "session"; inp.value = document.getElementById('sessionID').value; myform.appendChild(inp); nod.appendChild(myform); myform.submit(); nod.removeChild(myform); }
Если полученный с сервера файл требуется не сохранять, а вывести на экран, то хедер нужен немного другой:Код:#!/usr/bin/perl use DBI; use locale; use Encode; use CGI ':standard'; use Spreadsheet::WriteExcel; print "Content-Disposition: attachment; filename=data.xls\n"; print "Content-Type: application/x-force-download; name=\"data.xls\"\n\n"; my ($workbook, $worksheet, $tabformat); my @title = ('ID платежа','№ устройства','Владелец','Дата','Сумма'); $workbook = Spreadsheet::WriteExcel->new(\*STDOUT); $worksheet = $workbook->add_worksheet(); $tabformat = $workbook->add_format(); $tabformat->set_bold(1); $tabformat->set_align('center'); $tabformat->set_bg_color('silver'); $worksheet->set_column(0, 0, 15); $worksheet->set_column(1, 1, 50); $worksheet->set_column(2, 4, 20); for (my $i = 0; $i <= $#title; $i++) { $worksheet->write(0, $i, decode('utf8', $title[$i]), $tabformat); } for (my $i = 1; $i <= 5; $i++) { for (my $j = 0; $j <= 4; $j++) { $worksheet->write($i, $j, decode('utf8', "текст: $i, $j")); } }
Код:print "Content-type: application/vnd.ms-excel\n"; print "Content-Disposition: attachment; filename=data.xls\n\n";
-
Скрыть объявление
Друзья, в это тяжёлое и непонятное для всех нас время мы просим вас воздержаться от любых упоминаний политики на форуме, - этим ситуации не поможешь, а только возникнут ненужные ссоры и обиды. Это касается также шуток и юмора на тему конфликта. Пусть войны будут только виртуальными, а политики решают разногласия дипломатическим путём. С уважением, администрация Old-Games.RU.
-
Скрыть объявлениеЕсли Вы видите это сообщение, значит, вы ещё не зарегистрировались на нашем форуме.
Зарегистрируйтесь, если вы хотите принять участие в обсуждениях. Перед регистрацией примите к сведению:
- Не регистрируйтесь с никами типа asdfdadhgd, 354621 и тому подобными, не несущими смысловой нагрузки (ник должен быть читаемым!): такие пользователи будут сразу заблокированы!
- Не регистрируйте больше одной учётной записи. Если у вас возникли проблемы при регистрации, то вы можете воспользоваться формой обратной связи внизу страницы.
- Регистрируйтесь с реально существующими E-mail адресами, иначе вы не сможете завершить регистрацию.
- Обязательно ознакомьтесь с правилами поведения на нашем форуме, чтобы избежать дальнейших конфликтов и непонимания.
С уважением, администрация форума Old-Games.RU
Комментарии
Сортировать комментарии по