#javascript #html5 #xmlhttprequest
Тут я пытался что то навалять примерно так: var slice = file.slice(10, 100); // прочитать байты с 10 го по 99 й xhr.send(slice); //и отправить эти байты в запросе. Но такая модель не жизнеспособна! Как отослать на сервер не весь файл, а только нужную часть его? Или поставить на паузу закачку а потом либо отменить либо продолжить. С помощью javascript как можно это сделать? Спасибо.
Ответы
Ответ 1
Для загрузки нам нужно точно знать количество загруженных байт. Это может сообщить только сервер. Алгоритм возобновляемой загрузки Загрузкой файла будет заведовать объект Uploader, его примерный общий вид: function Uploader(file, onSuccess, onFail, onProgress) { // fileId уникальным образом идентифицирует файл // можно добавить идентификатор сессии посетителя, но он и так будет в заголовках var fileId = file.name + '-' + file.size + '-' + +file.lastModifiedDate; // сделать из fileId число (хеш, алгоритм неважен), мы будем передавать его в заголовке, // в заголовках разрешены только ASCII-символы fileId = hashCode(fileId); var errorCount = 0; // если количество ошибок подряд превысит MAX_ERROR_COUNT, то стоп var MAX_ERROR_COUNT = 6; var startByte = 0; var xhrUpload; var xhrStatus; function upload() { console.log("upload: check status"); xhrStatus = new XMLHttpRequest(); xhrStatus.onload = xhrStatus.onerror = function() { if (this.status == 200) { startByte = +this.responseText || 0; console.log("upload: startByte=" + startByte); send(); return; } // что-то не так if (errorCount++ < MAX_ERROR_COUNT) { setTimeout(upload, 1000 * errorCount); // через 1 сек пробуем ещё раз } else { onError(this.statusText); } }; xhrStatus.open("GET", "status", true); xhrStatus.setRequestHeader('X-File-Id', fileId); xhrStatus.send(); } function send() { xhrUpload = new XMLHttpRequest(); xhrUpload.onload = xhrUpload.onerror = function() { console.log("upload end status:" + this.status + " text:" + this.statusText); if (this.status == 200) { // успешное завершение загрузки onSuccess(); return; } // что-то не так if (errorCount++ < MAX_ERROR_COUNT) { setTimeout(resume, 1000 * errorCount); // через 1,2,4,8,16 сек пробуем ещё раз } else { onError(this.statusText); } }; xhrUpload.open("POST", "upload", true); // какой файл догружаем /загружаем xhrUpload.setRequestHeader('X-File-Id', fileId); xhrUpload.upload.onprogress = function(e) { errorCount = 0; onProgress(startByte + e.loaded, startByte + e.total); } // отослать, начиная с байта startByte xhrUpload.send(file.slice(startByte)); } function pause() { xhrStatus && xhrStatus.abort(); xhrUpload && xhrUpload.abort(); } this.upload = upload; this.pause = pause; } // вспомогательная функция: получение 32-битного числа из строки function hashCode(str) { if (str.length == 0) return 0; var hash = 0, i, chr, len; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; }; Аргументы для new Uploader: file Объект File API. Может быть получен из формы, либо как результат Drag’n’Drop. onSuccess, onFail, onProgress Функции-коллбэки, которые будут вызываться в процессе (onProgress) и при окончании загрузки. Подробнее про важные данные, с которыми мы будем работать в процессе загрузки: fileId Уникальный идентификатор файла, генерируется по имени, размеру и дате модификации. По нему мы всегда сможем возобновить загрузку, в том числе и после закрытия и открытия браузера. startByte С какого байта загружать. Изначально – с нулевого. errorCount / MAX_ERROR_COUNT Текущее число ошибок / максимальное число ошибок подряд, после которого загрузка считается проваленной. Алгоритм загрузки: Генерируем fileId из названия, размера, даты модификации файла. Можно добавить и идентификатор посетителя. Спрашиваем сервер, есть ли уже такой файл, и если да – сколько байт уже загружено? Отсылаем файл с позиции, которую сказал сервер. При этом загрузку можно прервать в любой момент, просто оборвав все запросы. Вы можете скачать пример и запустить локально для полноценной демонстрации:Ответ 2
Отправка файла по частям API файлов существенно облегчает отправку больших файлов. Методика такова: крупный файл разбивается на несколько мелких, которые затем отправляются с помощью XHR и собираются обратно на сервере. Примерно так же Gmail быстро отправляет большие прикрепленные файлы. Эта технология также позволяет обойти ограничение Google App Engine: 32 МБ на один HTTP-запрос. window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder; function upload(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function(e) { ... }; xhr.send(blobOrFile); } document.querySelector('input[type="file"]').addEventListener('change', function(e) { var blob = this.files[0]; const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes. const SIZE = blob.size; var start = 0; var end = BYTES_PER_CHUNK; while(start < SIZE) { // Note: blob.slice has changed semantics and been prefixed. See http://goo.gl/U9mE5. if ('mozSlice' in blob) { var chunk = blob.mozSlice(start, end); } else { var chunk = blob.webkitSlice(start, end); } upload(chunk); start = end; end = start + BYTES_PER_CHUNK; } }, false); })(); Источник
Комментариев нет:
Отправить комментарий