Google Drive возобновить загрузку с помощью JavaScript
Я пытаюсь загрузить файлы на Google Диск, используя клиентскую библиотеку API Google для JavaScript и возобновляемый тип загрузки.
Я проверяю подлинность и получаю URI загрузки успешно, но у меня возникли проблемы при отправке реальных данных. Если файл содержит только символы ASCII, файл успешно отправляется на накопитель, но в случае специальных символов (åäö) или двоичного файла (например, PNG) файл будет поврежден. Я думаю, что где-то в процессе файл кодируется в Unicode на стороне клиента.
Если я использую "btoa()" для кодирования необработанных данных в base64 и добавлю заголовок "Content-Encoding: base64" к запросу на отправку данных, файл загрузится нормально. Однако использование этого метода увеличивает накладные расходы на 33%, что довольно много, если планируемый размер загрузки файлов составляет от 100 МБ до 1 ГБ.
Вот несколько примеров кода:
Получение возобновляемого URI загрузки:
// Authentication is already done
var request = gapi.client.request({
"path": DRIVE_API_PATH, // "/upload/drive/v2/files"
"method": "POST",
"params": {
"uploadType": "resumable"
},
"headers": {
"X-Upload-Content-Type": self.file.type,
//"X-Upload-Content-Length": self.file.size
// If this is uncommented, the upload fails because the file size is
// different (corrupted file). Manually setting to the corrupted file
// size doesn't give 400 Bad Request.
},
"body": {
// self.file is the file object from <input type="file">
"title": self.file.name,
"mimeType": self.file.type,
"Content-Lenght": self.file.size,
}
});
Отправка всего файла за один раз:
// I read the file using FileReader and readAsBinaryString
// body is the reader.result (or btoa(reader.result))
// and this code is ran after the file has been read
var request = gapi.client.request({
"path": self.resumableUrl, // URI got from previous request
"method": "PUT",
"headers": {
//"Content-Encoding": "base64", // Uploading with base64 works
"Content-Type": self.file.type
},
"body": body
});
Я что-то пропустил? Можно ли загрузить файл в двоичном потоке? Я новичок в загрузке файлов в HTML и Javascript, и я не нашел примеров использования библиотеки Google Javascript с возможностью возобновляемой загрузки. Есть аналогичный вопрос в SO без ответов.
2 ответа
Типы BLOB-объектов являются горячей темой XMLHttpRequest
реализации, и они не являются по-настоящему зрелыми. Я бы порекомендовал вам придерживаться кодировки base64. Клиентская библиотека Google для JavaScript не поддерживает возобновляемую загрузку, поскольку очень маловероятно, что клиентское приложение на стороне браузера загружает очень большие файлы непосредственно в Google Drive.
Что работает
Чтобы загрузить двоичный двоичный объект, используйте gorsub/googleapi cors -upload-sample или мой gist-форк UploaderForGoogleDrive, который захватит access_token
из разрыва клиента для вас.
Вот уродливая смесь Promise и кода обратного вызова, которая работает для меня. В качестве предпосылки, gapi
,UploaderForGoogleDrive
, JSZip
должны быть загружены через <script>
теги. Фрагмент также пропускает инициализацию гапси и секреты API, которые также необходимы.
function bigCSV(){ // makes a string for a 300k row CSV file
const rows = new Array(300*1000).fill('').map((v,j)=>{
return [j,2*j,j*j,Math.random(),Math.random()].join(',');
});
return rows.join("\n");
}
function bigZip(){ // makes a ZIP file blob, about 8MB
const zip = new window.JSZip();
zip.folder("A").file("big.csv", bigCSV());
return zip.generateAsync({type:"blob", compression:"DEFLATE"});
// returns Promise<blob>
}
function upload2(zipcontent){
'use strict';
const parent = 'root';
const spaces = 'drive';
const metadata = {
name: 'testUpload2H.zip',
mimeType: 'application/zip',
parents: [parent]
};
const uploader = new window.UploaderForGoogleDrive({
file: zipcontent,
metadata: metadata,
params: {
spaces,
fields: 'id,name,mimeType,md5Checksum,size'
},
onProgress: function(x){
console.log("upload progress:",Math.floor(100*x.loaded/x.total));
},
onComplete: function(x){
if (typeof(x)==='string') x = JSON.parse(x);
// do something with the file metadata in x
console.log("upload complete: ");
},
onError: function(e){ console.log("upload error: ",e); }
});
uploader.upload();
}
function uploadZipFile(){
'use strict';
(bigZip()
.then(upload2)
);
}
Что не работает
По состоянию на ноябрь 2017 года загрузка двоичного двоичного объекта с gapi.client.request
вызов не будет работать из-за проблемы, когда gapi удаляет полезную нагрузку PUT
Я также пытался использовать base64 с gapi
, который работает. но хранит файлы base64, а не настоящие двоичные файлы; и API выборки в режиме cors, который работал наполовину, но вызывал ошибки, связанные с CORS, и скрытие ответов, по крайней мере для меня.