Resuming Google Drive downloads using javascript

I am trying to upload files to Google Drive using the Google APIs Client API Library for JavaScript and a renewable download type .

I authenticate and get the URI to download successfully, but I ran into problems sending actual data. If the file contains only ASCII characters, the file is successfully sent to disk, but in the case of special characters (åäö) or a binary file (for example, PNG), the file is damaged. I guess somewhere in the process the file is encoded in unicode on the client side.

If I use "btoa ()" to encode base64 raw data and add the header "Content-Encoding: base64" to the data send request, the file loads in order. However, using this method increases the overhead by 33%, which is quite a lot when the planned size of the downloaded files is from 100 MB to 1 GB.

Here are some sample code:

Obtaining a reload 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, } }); 

Sending the whole file in one go:

 // 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 }); 

Am I missing something? Can I upload a file to a binary stream? I am new to uploading files in HTML and Javascript, and I have not found any examples using the Google Javascript library with renewable downloads. There is a similar question in unanswered SO.

+2
source share
2 answers

Blob types are a hot topic for XMLHttpRequest implementations, and they are not very mature. I would recommend you stick with base64 encoding. The Google JavaScript client client does not support resuming downloads, because it is very unlikely that a client-side browser application will download very large files directly to Google Drive.

+1
source

What works

To download the binary blob, use github / googleapi cors-upload-sample or use my built-in fork, UploaderForGoogleDrive , which will select the access_token from the gapi client for you.

Here is an ugly mix of Promise code and callback that works for me. As a prerequisite, gapi , UploaderForGoogleDrive , JSZip must be loaded using <script> tags. The snippet also excludes gallis initialization and API secrets, which are also necessary.

 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) ); } 

What does not work

As of November 2017, loading a binary block with a call to gapi.client.request will not work, due to a problem where gapi removes the PUT payload

I also tried using base64 with gapi , which works. but embeds base64 files, not real binary files; and a cors mode select API that partially handled but created CORS related errors and hiding the answer, at least for me.

0
source

Source: https://habr.com/ru/post/1488648/


All Articles