【发布时间】:2020-05-26 16:03:49
【问题描述】:
我的代码有一个成功的工作版本,它允许用户选择一个文件并上传到我的 Google 云端硬盘。 我正在使用一种将文件分块上传为可恢复上传的方法,以绕过 50mb 的限制。它很棒!但它只会上传到我的 Google Drive 的根文件夹!
我一直在尝试实施this 解决方案,但接受的答案只是一个猜测(由回答的人承认),原始发帖人的评论说他们为使其工作所做的工作对我也不起作用.
我目前有它用于初始化要上传的文件:
xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&addParents=1XVNmZ7Q4vHLB7p9tTk0_rz7Z1VOwy_I8&removeParents=root");
这不会产生错误,但只是将文件放在根目录中。
我也尝试更改“恢复”的 PUT 请求,但如果我与原始 POST 不匹配或者如果我确实使它们相同,它会出现“找不到文件”的错误,它仍然只是上传到 root!
谷歌Documentation 说我所做的应该有效。我错过了什么?
如果有帮助,请在此处查看完整代码:
html:
<html>
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<title>Upload Files</title>
</head>
<body>
<div class="container-fluid mt-5 d-flex justify-content-center">
<div class="card py-2 px-5" style="width:550px">
<div class="card-head my-4 border-bottom border-top">
<h4 class="card-title">Upload File</h4>
</div></center>
<div class="card-body" id="resp">
<form id="fileuploadForm">
<li class="list-group-item"><input type="file" name="myFile" id="uploadfile"></li>
</form>
</div>
<center><div id="progress" class="display-4"></div></center>
</div>
</div>
<script>
const chunkSize = 5242880;
$('#uploadfile').on("change", function() {
var file = this.files[0];
if (file.name != "") {
var fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.onload = init;
fr.readAsArrayBuffer(file);
}
});
function init() {
$("#progress").text("Initializing.");
var fileName = this.fileName;
var fileSize = this.fileSize;
var fileType = this.fileType;
console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
var buf = this.result;
var chunkpot = getChunkpot(chunkSize, fileSize);
var uint8Array = new Uint8Array(buf);
var chunks = chunkpot.chunks.map(function(e) {
return {
data: uint8Array.slice(e.startByte, e.endByte + 1),
length: e.numByte,
range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
};
});
google.script.run.withSuccessHandler(function(at) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&addParents=1XVNmZ7Q4vHLB7p9tTk0_rz7Z1VOwy_I8&removeParents=root");
xhr.setRequestHeader('Authorization', "Bearer " + at);
xhr.setRequestHeader('Content-Type', "application/json");
xhr.send(JSON.stringify({
mimeType: fileType,
name: fileName,
}));
xhr.onload = function() {
doUpload({
location: xhr.getResponseHeader("location"),
chunks: chunks,
});
};
xhr.onerror = function() {
console.log(xhr.response);
};
}).getAt();
}
function doUpload(e) {
var chunks = e.chunks;
var location = e.location;
console.log("this stuff: " + location);
var cnt = 0;
var end = chunks.length;
var temp = function callback(cnt) {
var e = chunks[cnt];
var xhr = new XMLHttpRequest();
xhr.open("PUT", location, true);
xhr.setRequestHeader('Content-Range', e.range);
xhr.send(e.data);
xhr.onloadend = function() {
var status = xhr.status;
cnt += 1;
console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
$("#progress").text("Uploading: " + Math.floor(100 * cnt / end) + "%");
if (status == 308) {
callback(cnt);
} else if (status == 200) {
$("#progress").text("Done.");
} else {
$("#progress").text("Error: " + xhr.response);
}
};
}(cnt);
}
function getChunkpot(chunkSize, fileSize) {
var chunkPot = {};
chunkPot.total = fileSize;
chunkPot.chunks = [];
if (fileSize > chunkSize) {
var numE = chunkSize;
var endS = function(f, n) {
var c = f % n;
if (c == 0) {
return 0;
} else {
return c;
}
}(fileSize, numE);
var repeat = Math.floor(fileSize / numE);
for (var i = 0; i <= repeat; i++) {
var startAddress = i * numE;
var c = {};
c.startByte = startAddress;
if (i < repeat) {
c.endByte = startAddress + numE - 1;
c.numByte = numE;
chunkPot.chunks.push(c);
} else if (i == repeat && endS > 0) {
c.endByte = startAddress + endS - 1;
c.numByte = endS;
chunkPot.chunks.push(c);
}
}
} else {
var chunk = {
startByte: 0,
endByte: fileSize - 1,
numByte: fileSize,
};
chunkPot.chunks.push(chunk);
}
return chunkPot;
}
</script>
</body>
</html>
GS:
function doGet() {
return HtmlService.createHtmlOutputFromFile("index.html");
}
function getAt() {
return ScriptApp.getOAuthToken();
}
// This commented line is used for enabling Drive API and adding a scope of "https://www.googleapis.com/auth/drive".
// So please don't remove this.
// DriveApp.createFile();
【问题讨论】:
-
我必须为我糟糕的英语水平道歉。我无法理解
I also tried changing the PUT request for the "resuming" but It either errors out with "file not found" if I dont match the original POST or if I do make them the same, It still just uploads to root!。可以问一下它的详细情况吗?顺便说一句,如果您从其他站点或存储库中引用了脚本,我可以问您吗? -
感谢@Tanaike - 在回答您的第一个问题时,我很确定正在发生的是第一个函数通过执行 XMLHttpRequest.open 设置上传并使用 POST 作为方法。它上传一个块,然后用另一个 XMLHttpRequest.open 更新文件,但这次 PUT 作为方法(根据关于“更新现有文件”的 Google API 说明)link 为什么我不问编写代码的人?我只是打开了太多标签并关闭了错误的标签......现在我找不到它的位置:(
-
感谢您的回复。如果您的脚本修改了原始脚本并出现问题,则可以通过比较它们来了解问题的原因。所以我询问了原始脚本的源站点。这个怎么样?
-
我对原始文件的唯一更改是 HTML 以使其看起来更漂亮 - 当然,我使用的是我自己的文件夹 ID。原始文件并没有尝试选择文件夹,它只是为了绕过 Google 的 50mb 限制 - 所以唯一不同的是我试图将 addParents=1234.... 包含到我的POST 或 PUT 中的 URL。原始代码的 URL 直接在以下结尾:uploadType=resumable
-
“如果您的脚本修改了原始脚本并出现问题” 这是一个很好的观点,我知道您来自哪里,但我的更改确实不是问题做任何事情......它只是像原始脚本一样继续工作并上传到根文件夹。也许我不明白 Google 的 API 关于 addParents 的说法
标签: javascript html google-apps-script google-drive-api xmlhttprequest