You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

修改说明

  1. 指定上传文件夹:在初始化上传的JSON请求体中添加parents字段,值为目标文件夹folderX的ID(需替换代码中的示例ID),Drive API会将文件存入该文件夹。
  2. 返回访问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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:31:15