Google apps script 尝试使用服务帐户从GCS获取对象时获取404

Google apps script 尝试使用服务帐户从GCS获取对象时获取404,google-apps-script,google-cloud-platform,google-cloud-storage,Google Apps Script,Google Cloud Platform,Google Cloud Storage,我正在编写一个GoogleApps脚本代码,从GoogleCloudStorage下载一个对象并返回Blob。但是,在下面的调用中运行getGcsObjectBlobTest()函数会给我404响应代码,代码主体为“notfound” 我正在使用一个带有秘密JSON密钥的服务帐户进行身份验证。服务帐户具有项目的存储对象查看器角色和bucket的存储对象查看器角色/创建者角色。我没有设置任何表示“用户只需要从云IAM或ACL获得访问bucket或对象的权限”的ACL 有趣的是,如果我在谷歌云控制台

我正在编写一个GoogleApps脚本代码,从GoogleCloudStorage下载一个对象并返回Blob。但是,在下面的调用中运行
getGcsObjectBlobTest()
函数会给我404响应代码,代码主体为“notfound”

我正在使用一个带有秘密JSON密钥的服务帐户进行身份验证。服务帐户具有项目的存储对象查看器角色和bucket的存储对象查看器角色/创建者角色。我没有设置任何表示“用户只需要从云IAM或ACL获得访问bucket或对象的权限”的ACL

有趣的是,如果我在谷歌云控制台上的object details页面上获取的代码中将URL切换到“Link#2”,我会得到200个带有html主体的响应。所以我想我的IAM至少有一部分在工作

谁能告诉我发生了什么事

function getGcsObjectBlobTest(){
  var bucketName = 'vision_api_head_count';
  var objectName = 'Sample/Sample_01.jpg';

  getGcsObjectBlob(bucketName, objectName);
}


/*
 * Get Blob for a GCS object
 *
 * @param {string} bucketName - bucket name for the object
 * @param {string} objectName - name for the object
 * @returns Blob
 */
function getGcsObjectBlob(bucketName, objectName){
  var googleAppCredentials = getGoogleCredentials();
  var scope = 'https://www.googleapis.com/auth/devstorage.read_only';
  var token = getOAuth2TokenForGCP('annotatePrivateGcsImage', googleAppCredentials, scope);

  // Link #1: This URL is compliant with the official documentation. (https://cloud.google.com/storage/docs/json_api/v1/objects/get)
  var url = "https://storage.googleapis.com/storage/v1/b/" + bucketName + "/o/" + objectName + "?alt=media";

  // Link #2: This is "Link URL" from Google Cloud Console.
  // var url = "https://storage.cloud.google.com/" + bucketName + "/" + objectName + "?alt=media&orgonly=true&supportedpurview=organizationId";

  console.log(url);

  var options = {
    'method' : 'GET',
    'headers' : {
      'Authorization': 'Bearer ' + token,
    }
  }

  try{
    var blob = urlfetch(url, options, true).getBlob();
    console.log(blob.getName());
    console.log(blob.getContentType());
    console.log(blob.getBytes().length + " Bytes");

    return blob;
  }catch(e){
    throw new Error(e);
  }
}


/* Get OAuth2 token for specified credentials and scope
 * 
 * @requires {@link https://github.com/gsuitedevs/apps-script-oauth2|OAuth2 for Apps Script}
 * @param {string} serviceNamePrefix - prefix for the service name
 * @param {string} googleAppCredentials - JSON secret key for an account
 * @param {string} scope - {@link https://developers.google.com/identity/protocols/googlescopes|OAuth 2.0 Scopes for Google APIs}
 * @returns {string} OAuth 2.0 access token
 */
function getOAuth2TokenForGCP(serviceNamePrefix, googleAppCredentials, scope){
  var creds = JSON.parse(googleAppCredentials);

  var service = OAuth2.createService(serviceNamePrefix + "_" + creds.client_email)
      .setTokenUrl(creds.token_uri)
      .setPrivateKey(creds.private_key)
      .setIssuer(creds.client_email)
      .setSubject(creds.client_email)
      .setPropertyStore(PropertiesService.getScriptProperties())
      .setCache(CacheService.getScriptCache())
      .setLock(LockService.getScriptLock())
      .setScope(scope);

  if(service.hasAccess()){
    return service.getAccessToken();
  }else{
    console.error(service.getLastError());
    throw new Error('Could not get OAuth 2.0 access token!!');
  }
}

您使用了错误的端点,这就是您得到404(未找到错误)的原因。您正在使用名为“Authenticated Browser Downloads”的方法,但您正在调用的端点是用于JSON API的

在谷歌云控制台中查找URL

URL如下所示,但有几种变体:

https://storage.cloud.google.com/BUCKET_NAME/OBJECT_NAME


我刚刚通过将
encodeURIComponent()
应用于包含“/”的对象名,解决了这个问题。他们应该在文件中提到这一点

var url = "https://storage.googleapis.com/storage/v1/b/" + bucketName + "/o/" + encodeURIComponent(objectName) + "?alt=media";

编辑:输入错误

我试图构建一个服务器端应用程序来下载一个对象,所以JSON API就是我想要的。谢谢你努力回答我的问题@t、 toda-不过,我回答了你的问题,为什么你会得到404。