【问题标题】:Callback not defined when accessing Google Sheets using service account使用服务帐户访问 Google 表格时未定义回调
【发布时间】:2018-10-03 18:07:20
【问题描述】:

我正在尝试访问公共 Google 表格中的数据。该工作表对任何人都具有只读访问权限。我为此使用official Node.js client。我正在使用服务帐户对请求进行身份验证,因为我正在使用相同的服务帐户来访问另一个无法公开的工作表。

代码运行良好,但是当我将 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,当时服务帐户身份验证正在工作,但一旦我将其更新到 28.x,它就停止工作了。

有什么方法可以在 28.x googleapis node.js 客户端中使用服务帐户而不是 API 密钥?我无法降级它,因为我正在使用其他需要最新版本的 Google API。

【问题讨论】:

    标签: javascript node.js google-api google-sheets-api google-api-nodejs-client


    【解决方案1】:

    理论:sheets.values.get 的行为很奇怪,以至于 promisify 无法正常工作。

    可能的修复: 手动promisifygetData

    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);
        });
      });
    }
    

    【讨论】:

    • 感谢您的回复。我也这么想并尝试了回调方式,但它仍然给了我同样的错误。问题在于我验证数据的方式。
    【解决方案2】:

    好的,我再次查看了documentation,他们在about how to do it 的一处提到过。我以前使用过这样的 google-auth 库 -

    const GoogleAuth = require('google-auth-library');
    const googleAuth = new GoogleAuth();
    

    在之前的文档中提到过。我猜在工作表 API 的文档中,不记得了。但他们现在支持使用 googleapis 包和工作表 API 进行身份验证。因此,我所要做的就是切换到使用身份验证。所以这就是我现在获取 authClient 的方式,并且它正在测试中。

    const { google } = require('googleapis');
    const authClient = await google.auth.getClient({
        credentials: credentials,
        scopes: scopes
      });
    

    现在,我正在使用最新的googleapis package / Node.js client 获取正确的数据。

    所以问题是我如何获得 authClient。旧的方式似乎与最新的客户端不兼容。

    【讨论】:

    • PS:我需要一只橡皮鸭
    • ???????????
    猜你喜欢
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 2014-02-01
    • 2018-10-06
    • 2013-08-30
    • 1970-01-01
    相关资源
    最近更新 更多