2

I'm trying to upload files to Google Drive using Google APIs Client Library for JavaScript and resumable upload type.

I authenticate and get the upload URI successfully, but I ran into problems while sending the actual data. If the file contains only ASCII characters, the file is sent successfully to Drive, but in case of special characters (åäö) or binary file (such as PNG) the file gets corrupted. My guess would be that somewhere in the process the file is encoded to unicode in client side.

If I use "btoa()" to encode the raw data to base64 and add header "Content-Encoding: base64" to the data sending request, the file uploads fine. Using this method however increases the overhead for 33%, which is quite a lot when the planned upload size of files is 100MB to 1GB.

Here are some code examples:

Getting the resumable upload 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? Is it possible to upload file in binary stream? I am new to uploading files in HTML and Javascript and I haven't found any examples using Google Javascript library with resumable upload. There is similar question in SO with no answers.

4

2 回答 2

1

Blob 类型是XMLHttpRequest实现的热门话题,它们并不真正成熟。我建议您坚持使用 base64 编码。Google 的 JavaScript 客户端库不支持可恢复上传,因为客户端浏览器应用程序不太可能将非常大的文件直接上传到 Google Drive。

于 2013-07-29T12:59:41.203 回答
0

什么有效

要上传二进制 blob,请使用 github/googleapi 的cors-upload-sample或使用我的 gist fork UploaderForGoogleDrive,它将access_token为您从 gapi 客户端中获取。

这是对我有用的 Promise 和回调代码的丑陋组合。作为先决条件,gapi, UploaderForGoogleDrive,JSZip需要通过<script>标签加载。该片段还省略了 gapi 初始化和 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 年 11 月,由于gapi 删除 PUT 有效负载gapi.client.request的问题,无法通过调用上传二进制 blob

我也尝试过将 base64 与 一起使用gapi,这很有效。但存放 base64 文件,而不是真正的二进制文件;以及 cors 模式下的 fetch API,它工作了一半,但产生了与 CORS 相关的错误和响应隐藏,至少对我来说是这样。

于 2017-11-04T04:29:54.977 回答