Привет, я пытаюсь обновить документ 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... Кто-нибудь знает, это проблема с заголовком или есть способ ее исправить?
Я не знаю, возможно ли это сделать с помощью служебного ключа, или вам ДОЛЖЕН быть проверен пользователь, чтобы сделать это??
ПОКАЗАННО, если электронная почта служебного ключа имеет права на редактирование файла, он должен просто иметь возможность редактировать его по своему желанию.
@Tanaike Да, да, да, и сейчас я просто использую API привода. Я не знал, что в настоящее время существует разница между API документа и привода, я мог бы использовать все, что мне нужно.
Спасибо за ответ. Я мог понять ваш вопрос. Я предложил образец сценария в качестве ответа. Не могли бы вы подтвердить это? Если это не тот результат, который вы хотите, я извиняюсь.
Мой ответ показал вам результат, который вы хотите? Не могли бы вы рассказать мне об этом? Это также полезно для меня, чтобы учиться. Если это сработает, другие люди, у которых есть такая же проблема, как и вы, могут также обосновать ваш вопрос как вопрос, который можно решить. Если у вас есть вопросы для моего ответа еще, я извиняюсь. В то же время, могу я спросить вас о вашей текущей ситуации? Я хотел бы учиться, чтобы решить ваши проблемы.
@Tanaike Да, хотя я и сказал, что могу использовать googleAPI, но не упомянул, что мне было бы интересно сделать это без него; просто используя запросы GET, вы знаете, как это сделать?
Спасибо за ответ. Извините за неудобства. И мне очень жаль, что мой ответ не был вам полезен. К сожалению, файл нельзя перезаписать напрямую с помощью метода GET. Это спецификация. Прошу прощения за эту ситуацию. Если используются веб-приложения с использованием скрипта Google Apps, скрипт для перезаписи файла запускается путем запроса к веб-приложениям с помощью метода GET. В то время веб-приложения должны быть созданы с помощью скрипта Google Apps и развернуты. Как насчет этого?
@Tanaike Я думаю, что где-то в документации говорилось об использовании PUT вместо get, знаете ли вы, возможно ли это?
Это метод использования веб-приложений?
@Tanaike Нет, это был скрипт на стороне сервера, я предпочитаю НЕ использовать веб-приложения.
Насколько я понимаю, вы не хотите использовать веб-приложения со скриптом Google Apps. Могу я спросить вас о серверном скрипте?
@Tanaike NodeJS
В случае, если Drive API используется из скрипта node.js, необходимо использовать метод PATCH для перезаписи файла. Вы можете увидеть пример сценария в моем ответе. drive.files.update Drive API v3: Developers.google.com/drive/api/v3/reference/files/update
@Tanaike и без использования files.update?
Вы хотите перезаписать файл без использования метода files.update?
@Tanaike kir-ekct
Мне жаль. Я не могу понять насчёт kir-ekct. Могу ли я спросить вас о подробной информации об этом? Прошу прощения за мое знание языка.
@Tanaike Я просто имею в виду «правильно», лол, «kir-ekct», произнесите это ..
Я мог понять об этом. Хотя я искал способ прямой перезаписи файла без PUT, PATCH и POST, к сожалению, не нашел. В Drive API для этого используются методы PUT и PATCH. При пакетном обновлении Google Docs API для этого используется метод POST. Прошу прощения за эту ситуацию.
@Tanaike Нет, у меня нет проблем с использованием patch и put, пока это работает, как я могу это сделать? Когда я попробовал это просто не работает
Когда вы можете использовать метод PATCH, вы можете использовать сценарий в моем ответе. Я слышал, что вы можете использовать googleapis для node.js. Так что я использовал его. Как насчет этого?
@Tanaike Да, но знаете ли вы, как я могу использовать его без использования скрипта googleapis? В конечном счете, это просто запрос, похоже, мне не нужна для этого целая библиотека.
Если googleapis не используется, вы также не можете использовать new google.auth.JWT(). В этом случае вы хотите получить токен доступа без new google.auth.JWT(). Правильно ли я понимаю?





hi there с помощью Drive API, используя учетную запись службы.Я мог понять, как указано выше. Если я правильно понимаю, как насчет этого примера сценария? В этом примере скрипта я использовал метод 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);
});
Из ваших комментариев я понял, как выше. Если я правильно понимаю, как насчет этого примера сценария? При запуске этого скрипта проверьте следующие пункты.
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. Для этой ситуации я добавил пример сценария. Не могли бы вы подтвердить это? Если это не то, что вы хотите, я извиняюсь.
@bluejayke Мой дополнительный пример сценария показал вам результат, который вы хотите? Не могли бы вы рассказать мне об этом? Это также полезно для меня, чтобы учиться. Если у вас есть вопросы для моего ответа еще, я извиняюсь. В то же время, могу я спросить вас о вашей текущей ситуации? Я хотел бы учиться, чтобы решить ваши проблемы.
@bluejayke Могу ли я что-нибудь сделать по вашему вопросу? Если мой ответ не был полезен для вашей ситуации. Я должен извиниться и изменить его. Если вы можете сотрудничать, чтобы решить вашу проблему, я рад. Я хотел бы подумать о решении.
(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 Спасибо за ваш комментарий. Я обновил свой ответ. Не могли бы вы подтвердить это?
Чтобы правильно разобраться в вашей ситуации, могу ли я задать вам вопрос? 1. Вы хотите перезаписать документ Google текстом
hi there? 2. Доступен ли документ Google для учетной записи службы? 3. Можете ли вы использовать googleapis для Node.js? 4. Обязательно ли использовать только Drive API? Например, как насчет использования Google Docs API?