NodeJS Google Drive API, как обновить файл

Привет, я пытаюсь обновить документ Google с помощью NodeJS, используя API 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.info("doing Q", Q);

        }, timeTillNeedRefresh);

        tokens = t;
        console.info("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.info("DOING it later")
        Q.push(tmp);
        await refreshTokens();
    } else if (startedWaiting || timeTillNeedRefresh <= 0) {
        console.info("NOT for a while");
        Q.push(tmp);
    } else {
        console.info("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.info(b, "DID I DO IT?!");
                }
            });
        });
    }
}

Я попытался найти, что означает эта ошибка, но не смог найти ничего, связанного с nodejs... Кто-нибудь знает, это проблема с заголовком или есть способ ее исправить?

Я не знаю, возможно ли это сделать с помощью служебного ключа, или вам ДОЛЖЕН быть проверен пользователь, чтобы сделать это??

ПОКАЗАННО, если электронная почта служебного ключа имеет права на редактирование файла, он должен просто иметь возможность редактировать его по своему желанию.

Чтобы правильно разобраться в вашей ситуации, могу ли я задать вам вопрос? 1. Вы хотите перезаписать документ Google текстом hi there? 2. Доступен ли документ Google для учетной записи службы? 3. Можете ли вы использовать googleapis для Node.js? 4. Обязательно ли использовать только Drive API? Например, как насчет использования Google Docs API?

Tanaike 30.03.2019 01:17

@Tanaike Да, да, да, и сейчас я просто использую API привода. Я не знал, что в настоящее время существует разница между API документа и привода, я мог бы использовать все, что мне нужно.

B''H Bi'ezras -- Boruch Hashem 30.03.2019 01:36

Спасибо за ответ. Я мог понять ваш вопрос. Я предложил образец сценария в качестве ответа. Не могли бы вы подтвердить это? Если это не тот результат, который вы хотите, я извиняюсь.

Tanaike 30.03.2019 02:16

Мой ответ показал вам результат, который вы хотите? Не могли бы вы рассказать мне об этом? Это также полезно для меня, чтобы учиться. Если это сработает, другие люди, у которых есть такая же проблема, как и вы, могут также обосновать ваш вопрос как вопрос, который можно решить. Если у вас есть вопросы для моего ответа еще, я извиняюсь. В то же время, могу я спросить вас о вашей текущей ситуации? Я хотел бы учиться, чтобы решить ваши проблемы.

Tanaike 02.04.2019 00:35

@Tanaike Да, хотя я и сказал, что могу использовать googleAPI, но не упомянул, что мне было бы интересно сделать это без него; просто используя запросы GET, вы знаете, как это сделать?

B''H Bi'ezras -- Boruch Hashem 02.04.2019 01:31

Спасибо за ответ. Извините за неудобства. И мне очень жаль, что мой ответ не был вам полезен. К сожалению, файл нельзя перезаписать напрямую с помощью метода GET. Это спецификация. Прошу прощения за эту ситуацию. Если используются веб-приложения с использованием скрипта Google Apps, скрипт для перезаписи файла запускается путем запроса к веб-приложениям с помощью метода GET. В то время веб-приложения должны быть созданы с помощью скрипта Google Apps и развернуты. Как насчет этого?

Tanaike 02.04.2019 01:42

@Tanaike Я думаю, что где-то в документации говорилось об использовании PUT вместо get, знаете ли вы, возможно ли это?

B''H Bi'ezras -- Boruch Hashem 02.04.2019 01:55

Это метод использования веб-приложений?

Tanaike 02.04.2019 01:57

@Tanaike Нет, это был скрипт на стороне сервера, я предпочитаю НЕ использовать веб-приложения.

B''H Bi'ezras -- Boruch Hashem 02.04.2019 02:02

Насколько я понимаю, вы не хотите использовать веб-приложения со скриптом Google Apps. Могу я спросить вас о серверном скрипте?

Tanaike 02.04.2019 02:05

@Tanaike NodeJS

B''H Bi'ezras -- Boruch Hashem 02.04.2019 02:07

В случае, если Drive API используется из скрипта node.js, необходимо использовать метод PATCH для перезаписи файла. Вы можете увидеть пример сценария в моем ответе. drive.files.update Drive API v3: Developers.google.com/drive/api/v3/reference/files/update

Tanaike 02.04.2019 02:11

@Tanaike и без использования files.update?

B''H Bi'ezras -- Boruch Hashem 02.04.2019 02:15

Вы хотите перезаписать файл без использования метода files.update?

Tanaike 02.04.2019 02:16

@Tanaike kir-ekct

B''H Bi'ezras -- Boruch Hashem 02.04.2019 02:52

Мне жаль. Я не могу понять насчёт kir-ekct. Могу ли я спросить вас о подробной информации об этом? Прошу прощения за мое знание языка.

Tanaike 02.04.2019 03:14

@Tanaike Я просто имею в виду «правильно», лол, «kir-ekct», произнесите это ..

B''H Bi'ezras -- Boruch Hashem 02.04.2019 03:17

Я мог понять об этом. Хотя я искал способ прямой перезаписи файла без PUT, PATCH и POST, к сожалению, не нашел. В Drive API для этого используются методы PUT и PATCH. При пакетном обновлении Google Docs API для этого используется метод POST. Прошу прощения за эту ситуацию.

Tanaike 02.04.2019 03:23

@Tanaike Нет, у меня нет проблем с использованием patch и put, пока это работает, как я могу это сделать? Когда я попробовал это просто не работает

B''H Bi'ezras -- Boruch Hashem 02.04.2019 03:23

Когда вы можете использовать метод PATCH, вы можете использовать сценарий в моем ответе. Я слышал, что вы можете использовать googleapis для node.js. Так что я использовал его. Как насчет этого?

Tanaike 02.04.2019 03:28

@Tanaike Да, но знаете ли вы, как я могу использовать его без использования скрипта googleapis? В конечном счете, это просто запрос, похоже, мне не нужна для этого целая библиотека.

B''H Bi'ezras -- Boruch Hashem 02.04.2019 03:34

Если googleapis не используется, вы также не можете использовать new google.auth.JWT(). В этом случае вы хотите получить токен доступа без new google.auth.JWT(). Правильно ли я понимаю?

Tanaike 02.04.2019 03:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
22
2 700
1

Ответы 1

  • Вы хотите перезаписать существующий документ Google текстом hi there с помощью Drive API, используя учетную запись службы.
  • Документ Google используется совместно с учетной записью службы.
  • Вы можете использовать гугл апис.

Я мог понять, как указано выше. Если я правильно понимаю, как насчет этого примера сценария? В этом примере скрипта я использовал метод files.update Drive API.

Пример сценария:

Перед запуском сценария укажите путь к файлу json, загружаемому при создании учетной записи службы. И еще раз подтвердите идентификатор файла документа Google.

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.info(err);
        return;
    }
    console.info(res.data);
});

Примечание:

  • При запуске сценария существующий документ Google перезаписывается. Поэтому, пожалуйста, будьте осторожны. Я рекомендую использовать образец документа для тестирования.
  • Если этот скрипт не сработал, подтвердите следующие пункты.
    1. Drive API включен в консоли API.
    2. Можно использовать учетную запись службы.
    3. Документ Google используется совместно с учетной записью службы.
    4. Версия googleapis самая последняя.

Ссылка:

Редактировать:

  • Вы не хотите использовать googleapis.
  • Вы хотите перезаписать документ Google текстовым значением без использования googleapis.

Из ваших комментариев я понял, как выше. Если я правильно понимаю, как насчет этого примера сценария? При запуске этого скрипта проверьте следующие пункты.

  1. О сценарии,
    • Установите privateKey и clientEmail из файла JSON учетной записи службы.
    • Укажите идентификатор файла существующего документа Google, который вы хотите перезаписать.
  2. Drive API включен в консоли API.
  3. Можно использовать учетную запись службы.
  4. Документ Google используется совместно с учетной записью службы.
  5. Версия 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.info(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.info(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();

@bluejayke Я понял, что вы хотите перезаписать документ Google текстовым значением без использования googleapis. Для этой ситуации я добавил пример сценария. Не могли бы вы подтвердить это? Если это не то, что вы хотите, я извиняюсь.

Tanaike 02.04.2019 09:54

@bluejayke Мой дополнительный пример сценария показал вам результат, который вы хотите? Не могли бы вы рассказать мне об этом? Это также полезно для меня, чтобы учиться. Если у вас есть вопросы для моего ответа еще, я извиняюсь. В то же время, могу я спросить вас о вашей текущей ситуации? Я хотел бы учиться, чтобы решить ваши проблемы.

Tanaike 04.04.2019 02:59

@bluejayke Могу ли я что-нибудь сделать по вашему вопросу? Если мой ответ не был полезен для вашей ситуации. Я должен извиниться и изменить его. Если вы можете сотрудничать, чтобы решить вашу проблему, я рад. Я хотел бы подумать о решении.

Tanaike 06.04.2019 03:58
(node:3136) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
BartusZak 18.01.2021 10:24

@BartusZak Спасибо за ваш комментарий. Я обновил свой ответ. Не могли бы вы подтвердить это?

Tanaike 18.01.2021 14:00

Другие вопросы по теме