Google Apps Script上传至指定Drive文件夹并返回文件URL需求
Google Apps Script 文件上传表单优化方案
需求说明
- 将上传文件指定存储至名为
folderX的Google Drive文件夹 - 文件上传完成后返回其在Drive中的访问URL,用于编辑或管理操作
- 若上述方案无法实现,需将文件相关信息(ID、名称、URL)存储至名为
dbupload的数据库的dbuploadtable表中
原始代码
index.html
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.js"></script> <title>Resumable upload for Web Apps</title> </head> <body> <form> <input name="file" id="uploadfile" type="file"> </form> <div id="progress"></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"); 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; 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>
code.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 "https://www.googleapis.com/auth/drive". // So please don't remove this. // DriveApp.createFile();
修改后的代码(实现指定文件夹存储+返回访问URL)
index.html
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.js"></script> <title>Resumable upload for Web Apps</title> </head> <body> <form> <input name="file" id="uploadfile" type="file"> </form> <div id="progress"></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(); // 添加fields参数指定返回所需字段,包括webViewLink xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&fields=mimeType%2Cid%2Cname%2CwebViewLink%2Cparents"); xhr.setRequestHeader('Authorization', "Bearer " + at); xhr.setRequestHeader('Content-Type', "application/json"); xhr.send(JSON.stringify({ mimeType: fileType, name: fileName, parents: ["1xs9T_RfqZBS4i2JquCzy7qwumvrbPX4G"] // 替换为你的folderX的文件夹ID })); 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; 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) { // 解析响应获取文件访问URL并显示 var obj = JSON.parse(xhr.response); var url = obj.webViewLink; console.log(url); $("#progress").text("文件上传完成,访问链接:" + url); } 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>
修改说明
- 指定上传文件夹:在初始化上传的JSON请求体中添加
parents字段,值为目标文件夹folderX的ID(需替换代码中的示例ID),Drive API会将文件存入该文件夹。 - 返回访问URL:在请求URL中添加
fields参数,指定返回webViewLink字段;上传完成后解析响应JSON,提取该URL并显示在页面的进度区域。
备选方案:文件信息存入数据库
如果上述Drive上传方案无法实现,可将文件信息存入指定数据库。需在code.gs中添加以下函数,并在前端上传完成后调用:
code.gs 新增函数
function saveFileToDatabase(fileId, fileName, fileUrl) { // 配置数据库连接信息 var connectionUrl = "jdbc:mysql://你的数据库地址:端口/dbupload"; var user = "数据库用户名"; var password = "数据库密码"; try { var conn = Jdbc.getConnection(connectionUrl, user, password); var stmt = conn.createStatement(); // 插入数据到dbuploadtable表 var sql = "INSERT INTO dbuploadtable (file_id, file_name, file_url) VALUES ('" + fileId + "', '" + fileName + "', '" + fileUrl + "')"; stmt.executeUpdate(sql); stmt.close(); conn.close(); return "数据保存成功"; } catch(e) { console.log(e.toString()); return "数据保存失败:" + e.toString(); } }
前端调用修改
在doUpload函数的status == 200分支中添加调用:
var obj = JSON.parse(xhr.response); var url = obj.webViewLink; var fileId = obj.id; var fileName = obj.name; // 调用后端函数保存到数据库 google.script.run.withSuccessHandler(function(msg) { console.log(msg); }).saveFileToDatabase(fileId, fileName, url);
内容的提问来源于stack exchange,提问作者Ameen Halawani
相关产品推荐
相关产品推荐

