1. Друзья, в это тяжёлое и непонятное для всех нас время мы просим вас воздержаться от любых упоминаний политики на форуме, - этим ситуации не поможешь, а только возникнут ненужные ссоры и обиды. Это касается также шуток и юмора на тему конфликта. Пусть войны будут только виртуальными, а политики решают разногласия дипломатическим путём. С уважением, администрация Old-Games.RU.

    Скрыть объявление
  2. Если Вы видите это сообщение, значит, вы ещё не зарегистрировались на нашем форуме.

    Зарегистрируйтесь, если вы хотите принять участие в обсуждениях. Перед регистрацией примите к сведению:
    1. Не регистрируйтесь с никами типа asdfdadhgd, 354621 и тому подобными, не несущими смысловой нагрузки (ник должен быть читаемым!): такие пользователи будут сразу заблокированы!
    2. Не регистрируйте больше одной учётной записи. Если у вас возникли проблемы при регистрации, то вы можете воспользоваться формой обратной связи внизу страницы.
    3. Регистрируйтесь с реально существующими E-mail адресами, иначе вы не сможете завершить регистрацию.
    4. Обязательно ознакомьтесь с правилами поведения на нашем форуме, чтобы избежать дальнейших конфликтов и непонимания.
    С уважением, администрация форума Old-Games.RU
    Скрыть объявление

Direct file download

Автор: Helmut · 16 май 2019 ·
  1. Безопасность превыше всего! Именно поэтому постоянно приходится тратить время и творческую энергию на придумывание способов обхода ограничений безопасности в браузерах. В частности, AJAX. Инструмент был бы реально универсальным и многоцелевым, если бы не его функциональность не была искусственно ограничена по требованиям безопасности. Ну а поскольку альтернатив практически нет, постоянно приходится искать обходные пути.

    Ну ладно, операции с куки через AJAX мы реализовали, передачу файлов на сервер сделали при помощи API FormData, де-факто ставшего стандартом во всех браузерах, теперь пора подумать о противоположной задаче - загрузка файлов с сервера. Речь не идет о статичных файлах - там можно тупо передать ссылку на файл.

    Часто встречающаяся у бухов задача: передать на сервер (методом POST) некие данные, на основе которой сервер выполнит выборку из БД, оформит результат в виде таблицы MS Excel и вернет в браузер файл XLS. Выглядеть и работать это должно как можно проще: юзверь кликает по ссылке или кнопке, и у него открывается системное диалоговое окно для сохранения полученного файла на диск.

    Вообще, очевидное решение напрашивается само собой: серверный скрипт создает таблицу, сохраняет ее в файл на сервере, потом передает клиенту ссылку на этот файл. Но мы не будем искать простых путей и не хотим использовать костыли в виде промежуточных файлов. К тому же такое решение требует решения дополнительных задач в виде прав на чтение-запись на сервере и уникальных имен файлов, что не всегда удобно. Почему бы не выводить созданный файл непосредственно в STDOUT?

    Практически сразу выяснилось, что реализовать это через AJAX не получится от слова совсем. Аякс тупо не воспринимает HTTP хедеры типа force-download (в целях безопасности, ага), а попытки как-то обойти это быстро обросли таким лесом капризных и весьма ненадежных костылей, что от этой идеи пришлось отказаться.

    Поэтому мы пойдем другим путем. А именно - создание псевдо-формы и отправка ее на сервер обычным браузерным POST-запросом. Ну а асинхронность при желании можно добиться при помощи промисов. Как ни странно, иногда простые решения оказываются лучше, и такой финт ушами заработал именно так, как требуется.

    Итак, функция на жабаскрипте, принимающая в качестве аргументов имя формы и ссылку на серверный скрипт, причем вместе с GET-аргументами. Она создает клон формы, добавляет в нее новые поля (например, данные об авторизации юзверя) и отправляет методом POST, после чего ответ передается непосредственно в браузер, а сделавший свое дело клон убивается.

    Код:
    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);
    }
    
    Ну и скрипт на сервере, создающий XLS на основе полученных данных, присоединяющий к нему правильный хедер и возвращающий непосредственно в HTTP, без промежуточного сохранения на диск:

    Код:
    #!/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";
    
    kreol нравится это.

Комментарии

Чтобы оставить комментарий просто зарегистрируйтесь и станьте участником!
  1. На этом сайте используются файлы cookie, чтобы персонализировать содержимое, хранить Ваши предпочтения и держать Вас авторизованным в системе, если Вы зарегистрировались.
    Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie.
    Скрыть объявление