Сервлеты Java: загрузка Файла повреждается, когда пользователь перешел далеко от страницы

У меня есть сервлет, который позволяет пользователям загружать (потенциально большие) zip-файлы с веб-страницы. Если пользователь нажимает на ссылку, чтобы загрузить zip-файл, кодировать подобный следующему, выполняется в сервлете:

response.setContentType("application/zip");
response.setHeader("Content-disposition", "attachment; filename=foo.zip");
response.setHeader("Pragma", "");
response.setHeader("Cache-Control", "no-store");

ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
// write entries to the zip file...
...
out.close()

Однако, если пользователь обновится или перейдет далеко от страницы после того, как загрузка начинается и прежде чем она завершится (в Firefox 3.5.7), загрузка перестанет работать. Следующая ошибка открывается:

C:\blah\foo.zip.part не мог быть сохранен, потому что исходный файл не мог быть считан.

Попробуйте еще раз позже или свяжитесь с администратором сервера.

Какие-либо идеи о том, как я могу удостовериться загрузка, продолжаются в этом случае?

ОБНОВЛЕНИЕ: ссылка, которая инициирует загрузку, является простой ванильной ссылкой. Интересно, поведение отличается на IE. Нажимание на ссылки в другом месте на сайте (с в настоящее время загруженного экрана), кажется, не загружается (строка состояния браузера говорит "Ожидание https://mysite/clicked_linky.do..."), блокируясь, пока загрузка не завершается. Ввод другого URL в строку поиска или использование ярлыка/любимой ссылки перешли далеко от страницы, но загрузка продолжается как ожидалось. Только Firefox, кажется, отображает точное поведение, которое я описал выше, хотя блокирование IE не оптимально.

5
задан Jeff 14 January 2010 в 22:18
поделиться

2 ответа

Этого на самом деле не должно произойти. Загрузка засчитывается как отдельный запрос , который должен быть запущен в фоновом режиме независимо от родительской страницы после вызова. Как именно выполняется запрос на загрузку? Обычной ванильной ссылкой или ссылкой, которая (неправильно) запускает аяксический запрос на загрузку?

Во всяком случае, вы, по крайней мере, явно хотите иметь возможность возобновить загрузку. В этом случае вам необходимо отправить по крайней мере заголовки ответа Accept-Ranges, ETag и Last-Modified Last-Modified response headers along the download соответственно. Затем клиент может попросить возобновить загрузку, отправив заголовки запроса If-диапазона и Range с соответственно идентификатором файла и указанным диапазоном байтов, которые вы можете использовать в сочетании с RandomAccessFile для отправки оставшихся байтов. Дополнительную информацию и пример сервлета можно найти в этой статье .

Это теория. В вашем конкретном случае, это немного хитро, так как вы архивируете файлы на лету. Сначала нужно записать zip во временную папку файловой системы сервера на локальном диске, а затем передать из нее поток и, наконец, удалить файл только после успешного завершения загрузки (т.е. out.close() не выбрасывал IOException). Вы можете идентифицировать связанный zip-файл с помощью параметра запроса или pathinfo или, возможно, ключа в сеансе.

Обновление: согласно вашему обновлению: честно говоря, я не знаю и никогда не испытывал этого, но, по крайней мере, я могу сказать, что не только вы пострадали от этой проблемы. По крайней мере, реализация возможностей резюме, как описано выше, может быть решением этой конкретной проблемы, так как Firefox затем автоматически возобновит загрузку без рывков о незавершенной части.

Обновление 2: после небольшого размышления после прочтения обновления и поведения браузера, кажется, что существует довольно большой промежуток времени между обработкой фактического запроса и приходом заголовков ответа. Я не знаю точных деталей, как вы загружаете файлы, но это выглядит так , как будто существует временная затрата на сбор ZIP файлов (может быть, вы загружаете их из сетевой файловой системы или базы данных заранее?) и что вы устанавливаете/отправляете заголовки ответа только после того, как вы собрали все ZIP файлы. Попробуйте установить заголовки и выполнить output.flush() до, выполняя дорогостоящую задачу. Таким образом, браузер получит заголовки как можно быстрее и будет знать, чего он может ожидать.

6
ответ дан 14 December 2019 в 13:36
поделиться

Чтобы получить эту функциональность, необходимо выполнить некоторые специализированные функции SQL, зависящие от базы данных.

Если вы используете MySQL, вы можете добавить следующий код к вашей миграции после создать _ таблицу код:

execute("ALTER TABLE tbl AUTO_INCREMENT = 1000")
-121--2383277-

Ладно ответ из комментариев:

Похоже, Python не был настроен с --enable-ipv6 .

Это не должно быть проблемой ОС, потому что работает Python 3. Даже если ОС не поддерживает IPv6, кажется, что socket.AF _ INET6 всегда доступен (если он определен в файлах заголовков ОС). Ср. socketmodule.c , строка 4433 (в текущем исходном коде Python 2,6,4).

-121--4321217-

Я подозреваю, что это артефакт использования сервлетов - вероятно, в результате переназначения потока. Конечно, у меня нет такой проблемы с подобной настройкой, написанной в PHP (где каждый запрос обрабатывается (эффективно) новым процессом.

HTH

C.

0
ответ дан 14 December 2019 в 13:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: