(Node.js)表格v4 API值#batchGet函数忽略范围

时间:2018-09-17 14:01:21

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

我在Google Sheets API中发现了奇怪的行为(是问题吗?): Firebase函数日志未显示任何错误,但是values#batchGet函数忽略范围。它返回第一个范围内的整个工作表dataRange

batchGet "Try This API"

我根据代码Github: Sheets API batchGet ranges parameter issue编辑了代码

sheets.spreadsheets.values.batchGet({
  // your options
}, function (err, data, response) {
  console.log(response.req.res.request.url);
});

Node.js代码部分:

const sheets = google.sheets({ version: 'v4', access_token });  
// set auth as a global default:
google.options({ auth: jwt }); 

const request = {
  auth: jwt,
  spreadsheetId: 'xxxxx', //<---------- "Project Checklist" and "Control" sheets
  ranges: [
    "'Project Checklist'!B:K",
    "Control!A:F"
  ],
  majorDimension: "ROWS",
  dateTimeRenderOption: "FORMATTED_STRING",
  valueRenderOption: "FORMATTED_VALUE"
}

这包裹在一个Promise中...

sheets.spreadsheets.values.batchGet(request, (err, data, response) => {
  console.log("inside: sheets.spreadsheets.values.batchGet() --------"); 
  if (err) {
    console.log('The Sheets API returned an error: ' + err);
    //The API returned an error: Error: API key not valid. Please pass a valid API key.
    reject(err);
  };      
  try {
    console.log("response:-------------------------------");
    console.log(JSON.stringify(response));

    console.log("data.valueRanges:-------------------------------");
    console.log(data.valueRanges); 
    resolve(JSON.stringify(data.valueRanges));
  } catch (err) {
    console.log("Error processing Sheets API response: " + err);
    reject(err);
  }    
})

Log

Firebase日志:

Function execution took 3822 ms, finished with status code: 200
undefined
data.valueRanges:-------------------------------
undefined
response:-------------------------------
getJwt() --------------- OK

index.js

'use strict'
const functions = require('firebase-functions');
const { google } = require('googleapis');
var serviceAccount = require("./credentials/admin-service-account-key.json");

function getJwt() {
  // Define the required scopes.
  var scopes = [
    'https://www.googleapis.com/auth/spreadsheets'
  ];
  return new google.auth.JWT(
    serviceAccount.client_email,
    null,
    serviceAccount.private_key,
    scopes
  );
}

function getSpreadsheetData(jwt) {

  return new Promise((resolve, reject) => {
    jwt.authorize((error, access_token) => {
      if (error) {
        console.log('Error in jwt.authorize: ' + error);
        reject(error);
      } else {
        // access_token ready to use to fetch data and return to client
        const sheets = google.sheets({ version: 'v4', access_token });

        // set auth as a global default:
        google.options({ auth: jwt }); //<---------------------- 

        const request = {
          auth: jwt,
          spreadsheetId: 'xxxxxxxxxxxxxxxxxxxx', //<---------- Project Checklist / Control
          range: 'Control!A:F', //
        }

        sheets.spreadsheets.values.get(request, (err, response) => {
      console.log("inside: sheets.spreadsheets.values.get() -------------------------------");

          if (err) {
            console.log('The Sheets API returned an error: ' + err);
            //The API returned an error: Error: API key not valid. Please pass a valid API key.
            reject(err);
          };

          try {
            var numRows = response.data.values ? response.data.values.length : 0;
            console.log('%d rows retrieved.', numRows);

            console.log("response.data:-------------------------------");
            console.log(response.data.values);

            resolve(response.data.values);

          } catch (err) {
            console.log("Error processing Sheets API response: " + err);
            reject(err);
          }

        })

      }
    })
  })

}

function getSheetBatchData(jwt) {
  return new Promise((resolve, reject) => {
    jwt.authorize((error, access_token) => {
      if (error) {
        console.log('Error in jwt.authorize: ' + error);
        reject(error);
      } else {
        // access_token ready to use to fetch data and return to client
        const sheets = google.sheets({ version: 'v4', access_token });
        // set auth as a global default:
        google.options({ auth: jwt }); //<---------------------- 

        const request = {
          auth: jwt,
          spreadsheetId: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', //<---------- Project Checklist / Control
          ranges: [
            "Project Checklist!B:K",
            "Control!A:F"
          ],
          majorDimension: "ROWS",
          dateTimeRenderOption: "FORMATTED_STRING",
          valueRenderOption: "FORMATTED_VALUE"
        }

        /*
          sheets.spreadsheets.values.batchGet({
            // your options
          }, function (err, data, response) {
            console.log(response.req.res.request.url);
          });
        */

            //https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchGet
        sheets.spreadsheets.values.batchGet(request, (err, data, response) => {

          if (err) {
            console.log('The Sheets API returned an error: ' + err);
            //The API returned an error: Error: API key not valid. Please pass a valid API key.
            reject(err);
          };

          try {

            /*
             * Returns: Array: data.valueRanges = 
             * [
             *   "range": "....",
             *   "values": []
             * ]
             */

            console.log("response:-------------------------------");
            console.log(JSON.stringify(response));

            console.log("data.valueRanges:-------------------------------");
            console.log(data.valueRanges);
            resolve(JSON.stringify(data.valueRanges));

          } catch (err) {
            console.log("Error processing Sheets API response: " + err);
            reject(err);
          }

        });

      }
    })
  })
}



/* Working */
exports.getControlSheetData = functions.https.onCall((data, context) => {
  console.log("getData()---------------------------");
  if (!context.auth) {
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + 'while authenticated.');
  } else {
    console.log("context.auth ------------ OK");
    const uid = context.auth.uid;
    console.log(uid);

    var jwt = getJwt();
    console.log("getJwt() --------------- OK");

    return getSpreadsheetData(jwt); //<------------ Requested Spreadsheet's Data

  }
})

    /* Error */
    exports.getBatchData = functions.https.onCall((data, context) => {
  console.log("getBatchData()---------------------------");
      if (!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + 'while authenticated.');
      } else {
        console.log("context.auth ------------ OK");
        const uid = context.auth.uid;
        console.log(uid);

        var jwt = getJwt();
        console.log("getJwt() --------------- OK");

        return getSheetBatchData(jwt); //<------------ Requested Spreadsheet's Data

      }
    })

新测试:index.js

'use strict'
const functions = require('firebase-functions');
const { google } = require('googleapis');
var serviceAccount = require("./credentials/admin-service-account-key.json");

function getJwt() {
  // Define the required scopes.
  var scopes = [
    'https://www.googleapis.com/auth/spreadsheets'
  ];
  return new google.auth.JWT(
    serviceAccount.client_email,
    null,
    serviceAccount.private_key,
    scopes
  );
}

function getDataTest2(jwt) {
  jwt.authorize().then(access_token => {
    // access_token ready to use to fetch data and return to client
    const sheets = google.sheets({ version: 'v4', access_token });  
    // set auth as a global default:
    google.options({ auth: jwt }); //<----------------------  

    const request = {
      auth: jwt,
      spreadsheetId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
      ranges: [
        "Project Checklist!B:K",
        "Control!A:F"
      ],
      majorDimension: "ROWS",
      dateTimeRenderOption: "FORMATTED_STRING",
      valueRenderOption: "FORMATTED_VALUE"
    }

    function callback(data,resp) {
      try {
      console.log("inside callback-----------");

      console.log("returned data:--------------")
      console.log(data);

      console.log("returned resp:--------------")
      console.log(resp);

      console.log("expected data.valueRanges------------------------")
      console.log(data.valueRanges);  //<--------- expected data.valueRanges
      return JSON.stringify(data.valueRanges);

      } catch(err) {
        console.log('The Sheets API returned an error: ' + err);
        //The API returned an error: Error: API key not valid. Please pass a valid API key.
        return(err);
      }
    }

    sheets.spreadsheets.values.batchGet(request, callback);

  }).catch(error => {
    console.log('Error in jwt.authorize: ' + error);
    reject(error);
  })
}


exports.getBatchData = functions.https.onCall((data, context) => {
  console.log("getBatchData()---------------------------");
  if (!context.auth) {
    throw new functions.https.HttpsError('failed-precondition', 'The     function must be called ' + 'while authenticated.');
  } else {
    console.log("context.auth ------------ OK");
    const uid = context.auth.uid;
    console.log(uid);

    var jwt = getJwt();
    console.log("getJwt() --------------- OK");

    //return getSheetBatchData(jwt); //<------------ Requested Spreadsheet's Data
    return getDataTest2(jwt)

  }
})

Error

Firebase日志:

getJwt()--------------- OK
Function execution took 965 ms, finished with status code: 200

inside callback-----------
returned data: --------------
null
returned resp: --------------

{
  status: 200, statusText: 'OK', headers: { 'content-type': 'application/json; charset=UTF-8', vary: 'Origin, X-Origin, Referer', date: 'Tue, 18 Sep 2018 02:28:15 GMT', server: 'ESF', 'cache-control': 'private', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'alt-svc': 'quic=":443"; ma=2592000; v="44,43,39,35"', connection: 'close', 'transfer-encoding': 'chunked' }, config: { adapter: [Function: httpAdapter], transformRequest: { '0': [Function: transformRequest] }, transformResponse: { '0': [Function: transformResponse] }, timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: 2147483648, validateStatus: [Function], headers: { Accept: 'application/json, text/plain, */*', 'Accept-Encoding': 'gzip', 'User-Agent': 'google-api-nodejs-client/0.2.1 (gzip)', Authorization: 'Bearer ya29.c.ElocBg_A_xxxxxxxxxxxxxxxxxxxx' }, method: 'get', access_token: { access_token: 'ya29.c.ElocBg_A_xxxxxxxxxxxxxxxxxx', token_type: 'Bearer', expiry_date: 1537241286000, id_token: undefined, refresh_token: 'jwt-placeholder' }, url: 'https://sheets.googleapis.com/v4/spreadsheets/xxxxxxxxxxxxxxxxxxxxxxxxxxx/values:batchGet', paramsSerializer: [Function], data: undefined, params: { ranges: [Object], majorDimension: 'ROWS', dateTimeRenderOption: 'FORMATTED_STRING', valueRenderOption: 'FORMATTED_VALUE' } }, request: ClientRequest {
domain: null, _events: { socket: [Function], abort: [Function], aborted: [Function], error: [Function], timeout: [Function], prefinish: [Function: requestOnPrefinish] }, _eventsCount: 6, _maxListeners: undefined, output: [], outputEncodings: [], outputCallbacks: [], outputSize: 0, writable: true, _last: true, upgrading: false, chunkedEncoding: false, shouldKeepAlive: false, useChunkedEncodingByDefault: false, sendDate: false, _removedHeader: { }, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, _SNICallback: null, servername: null, npnProtocol: false, alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object], _eventsCount: 8, connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sheets.googleapis.com', _readableState: [Object], readable: false, domain: null, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 563, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: null, _httpMessage: [Circular], read: [Function], _consuming: true, write: [Function: writeAfterFIN], _idleNext: null, _idlePrev: null, _idleTimeout: -1 }, connection: TLSSocket {
  _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, _SNICallback: null, servername: null, npnProtocol: false, alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object], _eventsCount: 8, connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sheets.googleapis.com', _readableState: [Object], readable: false, domain: null, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 563, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: null, _httpMessage: [Circular], read: [Function], _consuming: true, write: [Function: writeAfte
...
expected data.valueRanges------------------------
The Sheets API returned an error: TypeError: Cannot read property     'valueRanges' of null

0 个答案:

没有答案