You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Google Apps Script WebApp中显示GCS私有图片(组织内可访问)

问题

我用Google Apps Script结合CardService开发了一款日历插件,插件包含若干输入框和提交按钮。提交信息后会调用带有图片的WebApp(基于Google Apps Script开发),该图片存储在Google Cloud Storage(GCS)存储桶中。需在不将图片设为公开的前提下,实现组织内所有成员可访问该图片,请问如何实现?

相关代码

let imgAction = CardService.newAction()
      .setFunctionName('openImage')
      .setParameters({cldImg: JSON.stringify(imgPath), preview: 'false'})

let submitButton = CardService.newTextButton()
      .setText('Submit')
      .setTextButtonStyle(CardService.TextButtonStyle.FILLED)
      .setBackgroundColor("#00b300")
      .setOnClickAction(imgAction)
      
let subBtn = CardService.newButtonSet()
      .addButton(submitButton);   
      
function openImage(){
 return CardService.newActionResponseBuilder()
      .setOpenLink(CardService.newOpenLink()
      .setUrl(imageUrl+'?param1='+param1+'&param2='+param2+'&param3='+param3)
      .setOpenAs(CardService.OpenAs.OVERLAY)
      .setOnClose(CardService.OnClose.RELOAD))
      .build();   
}

已尝试的方法及错误

我试过用Urlfetch获取imageUrl,但生成了重定向URL并抛出如下错误:

Exception: Request failed for https://script.google.com returned code 302. Truncated server response: <HTML>
<HEAD>
<TITLE>Moved Temporarily</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Moved Temporarily</H1>
The document has moved <A... (use muteHttpExceptions option to examine full response)
    at openFloorMap(formActions:386:31)

解决方案

1. 配置GCS存储桶组织权限

直接给整个组织分配存储桶的对象查看权限,无需公开图片:

  • 打开GCS控制台,找到目标存储桶
  • 进入「权限」标签页,点击「添加权限」
  • 主体选择你的组织域名(如your-domain.com),角色选择「Cloud Storage > Storage Object Viewer」
  • 保存后,组织内所有成员即可访问桶内所有图片

2. 生成GCS签名URL(精细权限控制)

如果需要限时访问或更灵活的权限,可通过Google Apps Script生成签名URL:

function generateSignedUrl(bucketName, fileName) {
  const expiration = new Date();
  expiration.setHours(expiration.getHours() + 1); // 设置1小时过期

  const signatureData = `GET\n\n\n${Math.floor(expiration.getTime()/1000)}\n/${bucketName}/${fileName}`;
  const privateKey = PropertiesService.getScriptProperties().getProperty('GCS_PRIVATE_KEY');
  const signed = Utilities.computeHmacSha256Signature(signatureData, privateKey);
  
  const encodedSignature = Utilities.base64Encode(signed)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
  
  return `https://storage.googleapis.com/${bucketName}/${fileName}?GoogleAccessId=${PropertiesService.getScriptProperties().getProperty('GCS_CLIENT_EMAIL')}&Expires=${Math.floor(expiration.getTime()/1000)}&Signature=${encodedSignature}`;
}

在openImage函数中,将imageUrl替换为这个签名URL即可。

3. 通过WebApp作为中间层访问

将WebApp部署权限设为「组织内任何人」,在WebApp中直接读取GCS图片并返回:

function doGet(e) {
  const imgPath = JSON.parse(e.parameter.cldImg);
  const bucket = StorageApp.getBucket('your-bucket-name');
  const file = bucket.getFile(imgPath);
  
  const blob = file.getBlob();
  return ContentService.createTextOutput(blob.getBytes())
    .setMimeType(blob.getContentType());
}

这种方式用WebApp的权限访问GCS,再将图片内容返回给用户,避免直接暴露GCS地址。

解决Urlfetch 302错误

使用WebApp的正式执行URL(而非编辑器预览URL),并在请求中启用重定向跟随:

const response = UrlFetchApp.fetch(imageUrl, {
  followRedirects: true,
  muteHttpExceptions: true
});

内容的提问来源于stack exchange,提问作者aks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 00:47:37