Запуск загрузки файла без запроса сервера

Привет,

Я работаю над JS-приложением, которое выполняет некоторую сложную работу и записывает некоторую информацию (фактически, до сотен строк) на <div>.

Моя цель - создать кнопку "Сохранить журнал", которая запускает диалог загрузки браузера, чтобы сохранить содержимое моего журнала <div>.

Более кратко, это требования к этой функции:

  • Конечный пользователь должен иметь полный контроль над файлом. Он/она должен иметь возможность сохранять/архивировать его для дальнейшего использования, отправлять его в отдел поддержки, чтобы получить помощь в решении какой-либо проблемы, загрузить ее обратно в приложение и т.д. Таким образом, API-интерфейс HTML5 Web Storage здесь не помогает (данные получить сохраненный в определенном браузером месте и не будет легко извлекаться, за исключением JS, который его создает).
  • Приложение должно работать в автономном режиме (по крайней мере, при некоторых обстоятельствах). Это и эффективность, вот почему я отбросил идею POSTing данных на сервер, чтобы вернуть его с заголовком "Content-disposition".
  • Файл должен быть помечен как text/plain, поэтому браузер может предлагать действия по умолчанию (например, "Открыть в блокноте" ), как при обычной загрузке файла. Это можно рассматривать как особый аспект первого требования.
  • Говорить пользователю о том, чтобы скопировать содержимое <div> в текстовый редактор и сохранить его там, безусловно, ужасно, и именно поэтому я пытаюсь избежать.

Я искал этот сайт, на сайтах WHATWG и W3C и в Интернете в целом без успеха. Это вообще возможно?

Самое близкое, что у меня есть, - это использовать data: url. Моя первая попытка, выполняющая POST-действие, не смогла получить тип контента, поэтому он вернется к эвристике UA. Мне было немного лучше, стиля ссылку <a>, чтобы выглядеть как кнопка и придать ей атрибут type, но тогда UA будет играть слишком умно и отображать контент вместо сохранения (и попросить пользователя сохранить файл из браузера на этом этапе становится еще хуже, чем при использовании подхода "копировать-вставить", поскольку сохранение страниц сильно варьируется между браузерами).

Если бы был какой-то способ объединить URL-адрес data: с подсказкой "content-disposition", все могло бы стать очень плавным.

С уважением, Herenvardo

Ответ 1

К сожалению, это не то, что вы можете сделать с обычными возможностями браузера. Что-то вроде flash или зависящего от браузера плагина доставит вам то, что вам нужно, но ограничения безопасности в javascript не позволят вам загружать произвольные данные, созданные в браузере.

Также URL-адрес 'data' не поддерживается во всех комбинациях браузера/версии. Я не уверен, ограничены ли ваши пользователи тем браузером, который они используют или нет, но могут ограничить то, что вы можете сделать с этим решением.

Ответ 2

Это решение немного запутанно, но будет работать для ваших нужд, возможно, это вариант.

Создайте собственный веб-сервер, который просто возвращает содержимое любого GET или POST как текстовое /plain.

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

Здесь доказательство сервера концепции в Java, которое будет делать именно это:

// After running this program, access with your browser at 127.0.0.1:8080

import java.net.*;
import java.io.*;

public class ReturnTextFile
{

    public static void main(String[] args)
    {

    try
    {
        ServerSocket server = new ServerSocket(8080);
        Socket connection = null;

        while (true)
        {

        try
        {
            connection = server.accept();

            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

            String input = in.readLine();

            // TODO: Clean up input

            Writer out = new OutputStreamWriter(connection.getOutputStream());

            String output = "HTTP/1.1 200 OK\n" +
                    "Connection: close\n" +
                    "Content-Disposition: attachment; filename=log.txt\n" +
                    "Content-Type: text/plain; charset=utf-8\n" +
                    "\n";

            output += input;

            out.write(output);

            out.flush();

            connection.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if (connection != null)
            {
            connection.close();
            }
        }

        }

    }
    catch (IOException ex)
    {
        ex.printStackTrace();
    }

    }
}

Ответ 3

Вы можете установить тип контента в URL data:, что-то вроде этого:

data:text/plain,this is some text

Тем не менее, проблема в том, что браузер автоматически отображает его как текст. У вас действительно есть два варианта, которые я вижу. Один из них заключается в том, что вы задаете тип двоичного типа, чтобы браузер не пытался его отобразить, или что у вас есть тип text/plain, и попросите пользователя щелкнуть правой кнопкой мыши и сохранить его. Возможно, что-то здесь может помочь?

Ответ 4

Я был на этом пути, и я также хотел сделать это исключительно на стороне клиента. Но это невозможно. Единственный способ запустить диалог сохранения без каких-либо проблем - это сделать запрос HTTP POST и ответить сервером заголовком content-disposition.

У меня есть желаемая функциональность в фрагментах кода на мой пыльный старый блог. У меня есть форма с одним скрытым полем, указывающим на пользовательский обработчик HTTP. Javascript захватывает внутренний текст блока кода, помещает его в скрытое поле и отправляет форму. Сервер отвечает всем телом запроса вместе с требуемыми заголовками. Нет обновления, вы щелкаете по нему, и вы получаете диалог сохранения. Отлично работает!