Сервлеты Java: загрузка файла прекращается, когда пользователь уходит со страницы - PullRequest
5 голосов
/ 14 января 2010

У меня есть сервлет, который позволяет пользователям загружать (потенциально большие) 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 не оптимальна.

Ответы [ 2 ]

6 голосов
/ 15 января 2010

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

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

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

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

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

0 голосов
/ 16 января 2010

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

НТН

C.

...