我正在尝试使用Google APIs Client Library for JavaScript和resumable upload type将文件上传到Google云端硬盘。
我验证并成功获取上传URI,但在发送实际数据时遇到了问题。如果文件仅包含ASCII字符,则文件将成功发送到Drive,但如果出现特殊字符(åäö)或二进制文件(如PNG),则文件会损坏。我的猜测是,在进程的某个地方,文件被编码为客户端的unicode。
如果我使用“btoa()”将原始数据编码为base64并向数据发送请求添加标题“Content-Encoding:base64”,则文件上传正常。然而,使用这种方法会增加33%的开销,当计划的文件上传大小为100MB到1GB时,这是非常多的。
以下是一些代码示例:
获取可恢复的上传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中有similar question没有答案。
答案 0 :(得分:1)
Blob类型是XMLHttpRequest
实现的热门话题,它们并不是真正成熟的。我建议你坚持使用base64编码。 Google的JavaScript客户端库不支持可恢复上传,因为客户端浏览器应用程序不太可能直接将非常大的文件上传到Google云端硬盘。
答案 1 :(得分:0)
要上传二进制blob,请使用github / googleapi cors-upload-sample或使用my gist fork, UploaderForGoogleDrive,这将从您的gapi客户端中获取access_token
。
这是一个丑陋的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月,由于issue where gapi removes the PUT payload
,使用gapi.client.request
电话上传二进制blob无法正常工作
我也尝试过将base64与gapi
一起使用,这有效。但存放base64文件,而不是真正的二进制文件;和cors模式下的fetch API,其中半工作但产生了与CORS相关的错误和响应隐藏,至少对我而言。