代码之家  ›  专栏  ›  技术社区  ›  B''H Bi'ezras -- Boruch Hashem

nodejsgoogledriveapi如何更新文件

  •  0
  • B''H Bi'ezras -- Boruch Hashem  · 技术社区  · 7 年前

    您好,我正在尝试使用Google Drive API使用NodeJS更新Google文档,我遇到以下错误:

    {
     "error": {
      "code": 500,
      "message": null
     }
    }
    

    var j = new google.auth.JWT(
        creds.client_email,
        null,
        creds.private_key,
        [
            "https://www.googleapis.com/auth/drive"
        ]
    );
    async function refreshTokens() {
        startedWaiting = true;
        return j.authorize((r,t) => {
            startedWaiting = false;
            timeTillNeedRefresh = t["expiry_date"] - Date.now();
            setTimeout(function() {
                refreshTokens();
            //    console.log("doing Q", Q);
    
            }, timeTillNeedRefresh);
    
            tokens = t;
            console.log("GOT A TOKEN", tokens);
            Q.forEach(x=>x());
            Q = [];
    
        });
    }
    
    async function start() {
        await refreshTokens();
    }
    start();
    function myFetch(opts) {
        if(!opts) opts = {};
        var cb = opts.cb || empty;
        var headers =  {
            'Accept-Encoding': 'gzip',
            'User-Agent': 'google-api-nodejs-client/0.7.2 (gzip)',
            Authorization:tokens.token_type +" "+ tokens.access_token,
            Accept:"application/json"
        };
        if(opts.headers) {
            for(k in opts.headers) {
                headers[k] = opts.headers[k];
            }
        }
        fetch(
            opts.url 
            || "",
        {
            method:opts.method || "GET",
            headers: headers
        })
            .then(res => res.text())
            .then(body => {
                cb(body);
    
            });
    }
    
    updateFile({
        id: "1vebqOamZ9QB4HqfUaQN-U9Zt4y33eij-I21glMvaPVQ",
        content: "hi there"
    });
    
    async function allFuncs(tmp) {
        if(tokens === null) {
            console.log("DOING it later")
            Q.push(tmp);
            await refreshTokens();
        } else if(startedWaiting || timeTillNeedRefresh <= 0) {
            console.log("NOT for a while");
            Q.push(tmp);
        } else {
            console.log("THIS is what should happen");
            start = Date.now();
            tmp();
        }
    }
    
    async function updateFile(opts) {
        var id = opts.id,
            content = opts.content || "";
        if(id) {
            allFuncs(() => {
                myFetch({
                    url:`https://www.googleapis.com/upload/drive/v3/files/${id}?uploadType=media`,
                    method:"PATCH",
                    headers: {
                        body: opts.content,
                        "Content-Type": "application/vnd.google-apps.document"
                    },
                    cb(b) {
                        console.log(b, "DID I DO IT?!");
                    }
                });
            });
        }
    }
    

    我试图查找此错误的含义,但找不到任何与nodejs相关的内容。。。 是否有人知道这是一个标题问题或有任何方法来解决它?

    0 回复  |  直到 7 年前
        1
  •  2
  •   Tanaike    5 年前
    • 您想用以下文本覆盖现有的Google文档: hi there 使用服务帐户使用驱动器API。
    • 你可以用googleapis。

    示例脚本:

    const stream = require('stream');
    const {google} = require('googleapis');
    const creds = require('###'); // Please set the json file path downloaded when the Service Account is created.
    const jwtClient = new google.auth.JWT(
        creds.client_email,
        null,
        creds.private_key,
        ['https://www.googleapis.com/auth/drive'],
        null
    );
    
    const id = "1vebqOamZ9QB4HqfUaQN-U9Zt4y33eij-I21glMvaPVQ"; // Please set the file ID of Google Document
    const content = "hi there"; // Please set the text.
    
    const drive = google.drive({version: 'v3', auth: jwtClient});
    const buf = Buffer.from(content, 'binary');
    const buffer = Uint8Array.from(buf);
    var bufferStream = new stream.PassThrough();
    bufferStream.end(buffer);
    const media = {
        mimeType: 'application/vnd.google-apps.document',
        body: bufferStream,
    };
    drive.files.update({
        fileId: id,
        media: media,
    }, (err, res) => {
        if (err) {
            console.log(err);
            return;
        }
        console.log(res.data);
    });
    

    注:

    • 运行脚本时,现有的Google文档将被覆盖。所以请小心这个。我建议使用示例文档进行测试。
    • 如果此脚本不起作用,请确认以下几点。
      1. 在API控制台上启用了驱动器API。
      2. 可以使用服务帐户。
      3. 谷歌文档与服务帐户共享。

    参考:

    • 你不想用googleapis。

    从你的评论中,我明白了上面的意思。如果我的理解是正确的,那么这个示例脚本怎么样?运行此脚本时,请确认以下几点。

    1. 关于剧本,
      • 请从服务帐户的JSON文件设置privateKey和clientEmail。
      • 请设置要覆盖的现有Google文档的文件ID。
    2. 在API控制台上启用了驱动器API。
    3. 谷歌文档与服务帐户共享。
    4. googleapis的版本是最新的。

    示例脚本:

    const cryptor = require('crypto');
    const request = require('request');
    
    // Get access token using Service Account
    function getAccessToken(serviceAccount) {
        const scopes = ["https://www.googleapis.com/auth/drive"];
        const url = "https://www.googleapis.com/oauth2/v4/token";
        const header = {
            alg: "RS256",
            typ: "JWT",
        };
        const now = Math.floor(Date.now() / 1000);
        const claim = {
            iss: serviceAccount.clientEmail,
            scope: scopes.join(" "),
            aud: url,
            exp: (now + 3600).toString(),
            iat: now.toString(),
        };
        const signature = Buffer.from(JSON.stringify(header)).toString('base64') + "." + Buffer.from(JSON.stringify(claim)).toString('base64');
        var sign = cryptor.createSign('RSA-SHA256');
        sign.update(signature);
        const jwt = signature + "." + sign.sign(serviceAccount.privateKey, 'base64');
        return new Promise(function(resolve, reject) {
            request({
                method: "post",
                url: url,
                body: JSON.stringify({
                    assertion: jwt,
                    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
                }),
            }, (err, res, body) => {
                if (err) {
                    console.log(err);
                    return;
                }
                const obj = JSON.parse(body);
                resolve(obj.access_token);
            });
        });
    }
    
    // Overwrite file in Google Drive
    function overWriting(object) {
        const metadata = {
            mimeType: "application/vnd.google-apps.document",
        };
        const url = "https://www.googleapis.com/upload/drive/v3/files/" + object.googleDocumentFileId + "?uploadType=multipart";
        const boundary = "xxxxxxxxxxx";
        var data = "--" + boundary + "\r\n";
        data += "Content-Disposition: form-data; name=\"metadata\"\r\n";
        data += "Content-Type: application/json; charset=UTF-8\r\n\r\n";
        data += JSON.stringify(metadata) + "\r\n";
        data += "--" + boundary + "\r\n";
        data += "Content-Disposition: form-data; name=\"file\"; filename=\"sample.txt\"\r\n";
        data += "Content-Type: text/plain" + "\r\n\r\n";
        const payload = Buffer.concat([
            Buffer.from(data, "utf8"),
            new Buffer(object.textData, 'binary'),
            Buffer.from("\r\n--" + boundary + "--", "utf8"),
        ]);
        const options = {
            method: 'patch',
            url: url,
            headers: {
                "Content-Type": "multipart/related; boundary=" + boundary,
                'Authorization': 'Bearer ' + object.accessToken,
            },
            body: payload,
        };
        request(options, (error, response, body) => {
            console.log(body);
        });
    
    }
    
    async function main() {
        const serviceAccount = {
            privateKey: "###", // private_key of JSON file retrieved by creating Service Account
            clientEmail: "###", // client_email of JSON file retrieved by creating Service Account
        };
        var object = {
            googleDocumentFileId: "###", // Set the file ID of the existing Google Document
            textData: "hi there",
        };
        const accessToken = await getAccessToken(serviceAccount);
        if (accessToken) {
            object.accessToken = accessToken;
            overWriting(object);
        }
    }
    
    main();
    
    推荐文章