使用服务帐户访问 Google 工作表时未定义回调
Callback not defined when accessing Google Sheets using service account
我正在尝试从 public Google Sheet 访问数据。 sheet 对任何人都具有只读访问权限。我为此使用 official Node.js client。我正在使用服务帐户对请求进行身份验证,因为我正在使用相同的服务帐户访问另一个 sheet,但无法进行 public.
代码工作正常,但是当我将 Node.js 客户端更新到最新版本后,它开始给我奇怪的错误。我已经为错误创建了一个缩小的示例,这是它的代码 -
/*eslint-disable no-console */
const { promisify } = require('util');
const GoogleAuth = require('google-auth-library');
const { google } = require('googleapis');
const googleAuth = new GoogleAuth();
const sheets = google.sheets('v4');
sheets.spreadsheets.values.getAsync = promisify(sheets.spreadsheets.values.get);
async function authorizeWithServiceAccount(serviceAccountKey, scopes) {
try {
let authClient = await authorize(serviceAccountKey, scopes);
return authClient;
} catch (err) {
console.error(err);
throw err;
}
}
function authorize(credentials, scopes) {
return new Promise((resolve, reject) => {
googleAuth.fromJSON(credentials, (err, client) => {
if (err) {
console.error(err);
reject(err);
return;
}
client.scopes = scopes;
client.authorize((err, result) => {
if (err) {
console.error(err);
reject(err);
return;
}
console.log(result, true);
resolve(client);
});
});
});
}
async function getData(auth, spreadsheetId, range) {
try {
return sheets.spreadsheets.values.getAsync({
auth: auth,
spreadsheetId: spreadsheetId,
range: range
});
} catch (e) {
console.error(e);
throw e;
}
}
const serviceAccountJson = require('../configs/keys/service_account'); //The service account json key
const spreadsheetId = 'SPREADSHEET_ID'; // Id of the sheet I am trying to access
const apiKey = 'THE_API_KEY'; //Any API key generated on Google's API console
const range = 'A:M';
async function init() {
let authClient = await authorizeWithServiceAccount(serviceAccountJson, [
'https://www.googleapis.com/auth/spreadsheets.readonly'
]);
return getData(authClient, spreadsheetId, range); //This doesn't work and throw error
// return getData(apiKey, spreadsheetId, range); //This does work and return all the data.
}
init()
.then(result => {
console.log('Received Data');
console.log(result.data);
})
.catch(e => console.error(e));
因此,如果我使用 API 密钥而不是服务帐户作为身份验证参数,我会按预期获得正确的数据。但是,一旦我改用服务帐户,result.data
就会变成 undefined
,然后出现此错误。
TypeError: callback is not a function
at JWT.OAuth2Client.postRequest (/Volumes/Projects/Work/node_modules/google-auth-library/lib/auth/oauth2client.js:341:9)
at postRequestCb (/Volumes/Projects/Work/node_modules/google-auth-library/lib/auth/oauth2client.js:297:23)
at Request._callback (/Volumes/Projects/Work/node_modules/google-auth-library/lib/transporters.js:113:17)
at Request.self.callback (/Volumes/Projects/Work/node_modules/request/request.js:186:22)
at emitTwo (events.js:126:13)
at Request.emit (events.js:214:7)
at Request.<anonymous> (/Volumes/Projects/Work/node_modules/request/request.js:1163:10)
at emitOne (events.js:116:13)
at Request.emit (events.js:211:7)
at IncomingMessage.<anonymous> (/Volumes/Projects/Work/node_modules/request/request.js:1085:12)
我之前使用的是 googleapis 库版本 25.x,当时服务帐户 auth 正在工作,但是一旦我将其更新为 28.x,它就停止工作了。
有什么方法可以在 28.x googleapis node.js 客户端中使用服务帐户而不是 API 密钥?我无法降级它,因为我正在使用其他需要最新版本的 Google API。
理论:sheets.values.get 做事非常奇怪,以至于 promisify
无法正常工作。
可能的修复:
手动 promisify
getData
async function getData(auth, spreadsheetId, range) {
return new Promise((resolve, reject) => {
sheets.spreadsheets.values.get({
auth: auth,
spreadsheetId: spreadsheetId,
range: range
}, (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
});
}
好的,我又看了看documentation and they have mentioned it at one place about how to do it。我以前像这样使用 google-auth 库 -
const GoogleAuth = require('google-auth-library');
const googleAuth = new GoogleAuth();
在之前的文档中提到过。我想在 sheet API 的文档中,不记得了。但是他们现在支持使用 googleapis 包和 sheets API 进行身份验证。因此,我所要做的就是切换到使用身份验证。这就是我现在获得 authClient 的方式,它正在测试中工作。
const { google } = require('googleapis');
const authClient = await google.auth.getClient({
credentials: credentials,
scopes: scopes
});
现在,我正在获取最新 googleapis package / Node.js client 的正确数据。
所以问题是我如何获得 authClient。旧的方式似乎与最新的客户端不兼容。
我正在尝试从 public Google Sheet 访问数据。 sheet 对任何人都具有只读访问权限。我为此使用 official Node.js client。我正在使用服务帐户对请求进行身份验证,因为我正在使用相同的服务帐户访问另一个 sheet,但无法进行 public.
代码工作正常,但是当我将 Node.js 客户端更新到最新版本后,它开始给我奇怪的错误。我已经为错误创建了一个缩小的示例,这是它的代码 -
/*eslint-disable no-console */
const { promisify } = require('util');
const GoogleAuth = require('google-auth-library');
const { google } = require('googleapis');
const googleAuth = new GoogleAuth();
const sheets = google.sheets('v4');
sheets.spreadsheets.values.getAsync = promisify(sheets.spreadsheets.values.get);
async function authorizeWithServiceAccount(serviceAccountKey, scopes) {
try {
let authClient = await authorize(serviceAccountKey, scopes);
return authClient;
} catch (err) {
console.error(err);
throw err;
}
}
function authorize(credentials, scopes) {
return new Promise((resolve, reject) => {
googleAuth.fromJSON(credentials, (err, client) => {
if (err) {
console.error(err);
reject(err);
return;
}
client.scopes = scopes;
client.authorize((err, result) => {
if (err) {
console.error(err);
reject(err);
return;
}
console.log(result, true);
resolve(client);
});
});
});
}
async function getData(auth, spreadsheetId, range) {
try {
return sheets.spreadsheets.values.getAsync({
auth: auth,
spreadsheetId: spreadsheetId,
range: range
});
} catch (e) {
console.error(e);
throw e;
}
}
const serviceAccountJson = require('../configs/keys/service_account'); //The service account json key
const spreadsheetId = 'SPREADSHEET_ID'; // Id of the sheet I am trying to access
const apiKey = 'THE_API_KEY'; //Any API key generated on Google's API console
const range = 'A:M';
async function init() {
let authClient = await authorizeWithServiceAccount(serviceAccountJson, [
'https://www.googleapis.com/auth/spreadsheets.readonly'
]);
return getData(authClient, spreadsheetId, range); //This doesn't work and throw error
// return getData(apiKey, spreadsheetId, range); //This does work and return all the data.
}
init()
.then(result => {
console.log('Received Data');
console.log(result.data);
})
.catch(e => console.error(e));
因此,如果我使用 API 密钥而不是服务帐户作为身份验证参数,我会按预期获得正确的数据。但是,一旦我改用服务帐户,result.data
就会变成 undefined
,然后出现此错误。
TypeError: callback is not a function
at JWT.OAuth2Client.postRequest (/Volumes/Projects/Work/node_modules/google-auth-library/lib/auth/oauth2client.js:341:9)
at postRequestCb (/Volumes/Projects/Work/node_modules/google-auth-library/lib/auth/oauth2client.js:297:23)
at Request._callback (/Volumes/Projects/Work/node_modules/google-auth-library/lib/transporters.js:113:17)
at Request.self.callback (/Volumes/Projects/Work/node_modules/request/request.js:186:22)
at emitTwo (events.js:126:13)
at Request.emit (events.js:214:7)
at Request.<anonymous> (/Volumes/Projects/Work/node_modules/request/request.js:1163:10)
at emitOne (events.js:116:13)
at Request.emit (events.js:211:7)
at IncomingMessage.<anonymous> (/Volumes/Projects/Work/node_modules/request/request.js:1085:12)
我之前使用的是 googleapis 库版本 25.x,当时服务帐户 auth 正在工作,但是一旦我将其更新为 28.x,它就停止工作了。
有什么方法可以在 28.x googleapis node.js 客户端中使用服务帐户而不是 API 密钥?我无法降级它,因为我正在使用其他需要最新版本的 Google API。
理论:sheets.values.get 做事非常奇怪,以至于 promisify
无法正常工作。
可能的修复:
手动 promisify
getData
async function getData(auth, spreadsheetId, range) {
return new Promise((resolve, reject) => {
sheets.spreadsheets.values.get({
auth: auth,
spreadsheetId: spreadsheetId,
range: range
}, (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
});
}
好的,我又看了看documentation and they have mentioned it at one place about how to do it。我以前像这样使用 google-auth 库 -
const GoogleAuth = require('google-auth-library');
const googleAuth = new GoogleAuth();
在之前的文档中提到过。我想在 sheet API 的文档中,不记得了。但是他们现在支持使用 googleapis 包和 sheets API 进行身份验证。因此,我所要做的就是切换到使用身份验证。这就是我现在获得 authClient 的方式,它正在测试中工作。
const { google } = require('googleapis');
const authClient = await google.auth.getClient({
credentials: credentials,
scopes: scopes
});
现在,我正在获取最新 googleapis package / Node.js client 的正确数据。
所以问题是我如何获得 authClient。旧的方式似乎与最新的客户端不兼容。