在 Google Apps Script 部署 「一鍵生成 PPTX」 專案
以下內容示範 最少改動 即可將原始 HTML 搬到 GAS Web App,不再被 CSP 或 CORS 擋下。
一、為什麼在 GAS 會被擋?
| 問題 | 背後機制 | 解法概要 |
|---|---|---|
外部 <script> 被攔 |
Web App 的 CSP 只允許同源腳本 | 自己當 Proxy: 用 UrlFetchApp 抓 CDN,再以 /exec?lib=xxx 回前端 |
| API Key 寫在瀏覽器端 | 金鑰外洩 / CORS 預檢失敗 | 搬到伺服器: 用 google.script.run 讓後端呼叫 AI |
| base64 圖片太大 | 部分 sandbox 對 data URI 有限制 |
可行;若失敗改用後端轉檔 |
二、四步驟流程
步驟 1|建立檔案結構
📁 專案
├─ Code.gs ← 後端主程式
├─ libs.gs ← CDN 代理 / 快取
├─ Index.html ← 畫面 (移除外部 <script>)
└─ app.js.html ← 原本的 JS 內容
步驟 2|後端 Code.gs
function doGet(e){
if(e.parameter.lib) return proxyLib(e.parameter.lib);
return HtmlService
.createTemplateFromFile('Index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function include(fn){return HtmlService.createHtmlOutputFromFile(fn).getContent();}
function proxyLib(name){
const map={reveal:'https://cdn.jsdelivr.net/…/reveal.min.js',…};
const url=map[name];
const cache=CacheService.getScriptCache();
let js=cache.get(url);
if(!js){js=UrlFetchApp.fetch(url).getContentText();cache.put(url,js,21600);}
return ContentService.createTextOutput(js).setMimeType(ContentService.MimeType.JAVASCRIPT);
}
並將 AI 呼叫包裝成 aiGenerateSlides()、aiGenerateImage() 兩支函式。
步驟 3|前端 Index.html 與 app.js.html
- Index.html: 保留結構,將所有 CDN 以
<script src="?lib=reveal">方式引用。 - app.js.html: 把所有
fetch()改用google.script.run叫後端函式。
步驟 4|部署
- 在 專案設定 → 連線權限 同意 UrlFetch 範圍。
- 部署 → 新部署 → Web App:執行身分選「自己」,存取權選「任何擁有連結的人」。
- 點「部署」取得 URL,即可使用。
三、常見攔截原因 & 解法
| 錯誤訊息 | 立刻檢查 | 解法 |
|---|---|---|
| CSP Refused to load script… | <script> 是否仍指外網 | 確認已改成 ?lib=xxx |
| UrlFetchApp 403 | AI API Key 或配額 | 在 Script Properties 更新密鑰 |
| CORS blocked by browser | 前端是否還在 fetch x.ai | 改用 google.script.run |
| PPTX 圖片缺失 | img 是否 fully loaded | await img.complete 後再截圖 |
四、額外小技巧
- 單檔≤50 KB: 拆成多個
.html模板避免大小限制。 - CDN 快取:
CacheService每 6 小時更新一次即可。 - 圖片過大: 後端轉 blob → base64,可減少跨域問題。
- 嵌入 Sites/LMS: 已開
ALLOWALL,可<iframe>直接用。
以上就是完整教學,祝部署順利!🎉