Обратный вызов не определен при доступе к Google Таблицам с использованием учетной записи службы

Я пытаюсь получить доступ к данным из общедоступной таблицы Google. Лист имеет доступ только для чтения для всех. Для этого я использую официальный клиент Node.js. Я использовал учетную запись службы для аутентификации запроса, так как я использую ту же учетную запись службы для доступа к другому листу, который не может быть опубликован.

Код работал нормально, но как только я обновил клиент 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, он перестал работать.

Есть ли способ использовать учетную запись службы вместо ключа API в узле 28.x googleapis .js клиент? Я не могу перейти на более раннюю версию, так как использую другие API Google, для которых требуется последняя версия.


person noob    schedule 23.04.2018    source источник


Ответы (2)


Хорошо, я снова просмотрел документацию и они упомянули об этом в одном месте о том, как сделать это. Раньше я использовал библиотеку google-auth вот так -

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

о котором упоминалось в предыдущей документации. Я предполагаю, что в документации API листов, не могу вспомнить. Но теперь они поддерживают аутентификацию с использованием пакета googleapis вместе с API листов. Таким образом, все, что мне нужно было сделать, это переключиться на использование auth. Вот как я сейчас получаю authClient, и он работает в тесте.

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

Теперь я получаю правильные данные с помощью последней версии пакета googleapis / клиента Node.js.

Итак, проблема заключалась в том, как получить authClient. Похоже, что старый способ несовместим с последним клиентом.

person noob    schedule 23.04.2018
comment
PS: мне нужна резиновая уточка - person noob; 23.04.2018

Теория: sheet.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);
    });
  });
}
person generalhenry    schedule 23.04.2018
comment
Спасибо за ответ. Я подумал то же самое и попытался использовать обратный вызов, но он все равно дал мне ту же ошибку. Проблема заключалась в способе аутентификации данных. - person noob; 23.04.2018