這是第 27 次的延伸,不是標準驗收前置。沒有 Google 帳號、Workspace 權限受限或課堂網路不穩時,維持 mock 模式即可完成本堂核心能力。
官方依據:Apps Script Web App 以 doPost(e) 接收 POST,部署後使用 /exec URL;/dev 測試網址只開放有專案編輯權限的人。Web Apps 官方說明、Content Service 官方說明
1. 準備專用測試 Sheet
- 建立一份不含個資的 Google Sheet。
- 第一列建立
createdAt、id、type、text四個欄位。 - 由「擴充功能 → Apps Script」開啟綁定專案。
2. 建立 doPost
將下列程式貼入 Apps Script。它會檢查必要欄位,再把一筆變更寫入目前試算表。
function jsonResponse(payload) {
return ContentService.createTextOutput(JSON.stringify(payload))
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
try {
const change = JSON.parse(e.postData.contents);
if (!change.id || !change.type || typeof change.text !== "string") {
throw new Error("缺少 id、type 或 text");
}
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sheet.appendRow([new Date(), change.id, change.type, change.text]);
return jsonResponse({ ok: true, id: change.id });
} catch (error) {
return jsonResponse({ ok: false, error: String(error.message) });
}
}
3. 部署 Web App
- 選「部署 → 新增部署作業」。
- 類型選 Web app。
- 依課堂帳號政策選擇最小必要存取範圍;不要用含個資的正式 Sheet 測試。
- 完成授權後複製結尾為
/exec的 URL。 - 程式更新後要建立新版本或更新部署,不能只儲存程式碼。
禁止把 OAuth token、帳號密碼或敏感試算表內容放進前端。Web App 若以部署者身分執行,就會使用部署者權限寫入資料,必須更審慎限制用途。
4. 建立 gasSend
在自己的延伸分支保留 mockSend(),另外加入以下函數;不要把真實 URL commit 到公開教材範例。
const GAS_URL = "貼上你自己的 /exec URL";
async function gasSend(change) {
const response = await fetch(GAS_URL, {
method: "POST",
headers: { "Content-Type": "text/plain;charset=utf-8" },
body: JSON.stringify(change),
});
const result = await response.json();
if (!result.ok) throw new Error(result.error || "GAS 寫入失敗");
return result;
}
把 syncQueue() 中的 mockSend(change) 暫時換成 gasSend(change)。若真實服務失敗,失敗項仍必須留在 queue,不能因為換了 sender 就改變復原規則。
5. 驗收證據
- Network 面板可看到對
/exec的 POST。 - 回應 JSON 為
{ "ok": true, "id": "..." }。 - Sheet 新增一列,id 與送出資料一致。
- 故意填錯 URL 時,queue 仍保留失敗項。
- 修回 URL 後重試,成功項才從 queue 移除。
只截 Sheet 畫面不足以證明前端同步流程;必須同時具備 Network 回應、queue 狀態與 Sheet 新列三項證據。