<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>模組一：Apps Script 地基 on Tarragon</title><link>https://tarrragon.github.io/blog/automation/01-apps-script-basics/</link><description>Recent content in 模組一：Apps Script 地基 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 06 Jul 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/automation/01-apps-script-basics/index.xml" rel="self" type="application/rss+xml"/><item><title>Apps Script 是什麼、跟一般伺服器差在哪</title><link>https://tarrragon.github.io/blog/automation/01-apps-script-basics/what-is-apps-script/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/automation/01-apps-script-basics/what-is-apps-script/</guid><description>&lt;p>Apps Script 是 Google 托管的 JavaScript 執行環境：你寫的程式碼跑在 Google 的伺服器上、用 V8 引擎執行，對個人 Google 帳號免費。它的定位是「膠水」——用少量程式碼把 Google 的服務（試算表、Gmail、日曆、雲端硬碟）跟外部串起來，補上這些服務單靠介面做不到的自動化。對流量統計這個案例，它扮演的是接住 beacon、把資料寫進 Sheet 的接收端。&lt;/p>
&lt;h2 id="沒有常駐程序跟一般伺服器最大的差別">沒有常駐程序：跟一般伺服器最大的差別&lt;/h2>
&lt;p>Apps Script 跟一台伺服器最根本的差別是&lt;strong>沒有一個常駐、屬於你的程序&lt;/strong>。一般伺服器是一支持續執行的程式，開機後一直在記憶體裡等請求；Apps Script 的程式碼平時不執行，只在被觸發（有人打 web app 網址、觸發器到點、你手動按執行）時才啟動一個執行實例，跑完就結束。這個模型帶來幾個要先知道的取捨：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>不必管主機&lt;/strong>：沒有作業系統要維護、沒有開關機、沒有閒置費用。程式碼不跑時完全不佔資源。&lt;/li>
&lt;li>&lt;strong>每次執行是獨立的&lt;/strong>：兩次執行之間，記憶體裡的變數不會保留。要跨執行記住東西，得寫進外部儲存（Sheet、&lt;code>PropertiesService&lt;/code>、Drive）。這跟伺服器可以用行程內記憶體 cache 是相反的。&lt;/li>
&lt;li>&lt;strong>有執行上限&lt;/strong>：單次執行最長 6 分鐘、同時併發有數量限制。長時間或高併發的工作不適合，細節見&lt;a href="https://tarrragon.github.io/blog/automation/knowledge-cards/execution-quota/" data-link-title="Execution Quota（執行配額）" data-link-desc="Apps Script 個人帳號的執行時間、同時併發與觸發器每日總時間上限，決定免費膠水層能承受多大的量">執行配額&lt;/a>。&lt;/li>
&lt;/ul>
&lt;p>理解「沒有常駐程序」才知道 Apps Script 適合什麼：短、偶發、由事件觸發的工作，例如「接一則 beacon 寫一列」「每天彙總一次」。不適合的是需要持續連線、低延遲、或狀態常駐記憶體的服務。&lt;/p>
&lt;h2 id="容器綁定-vs-獨立專案">容器綁定 vs 獨立專案&lt;/h2>
&lt;p>Apps Script 專案有兩種存在形式，差別在「它跟一個 Google 檔案綁不綁定」。&lt;/p>
&lt;p>&lt;strong>容器綁定（container-bound）&lt;/strong> 的專案依附在一個具體檔案上——從某張試算表的 &lt;code>擴充功能 → Apps Script&lt;/code> 開出來的專案，就綁定那張試算表。它的好處是程式裡用 &lt;code>SpreadsheetApp.getActiveSpreadsheet()&lt;/code> 直接拿到那張表，不必記檔案 ID；流量統計用這種，程式跟資料表天生綁在一起，最省事。它也能存取容器檔案特有的事件（例如試算表的 &lt;code>onEdit&lt;/code>、表單的 &lt;code>onFormSubmit&lt;/code>）。&lt;/p>
&lt;p>&lt;strong>獨立專案（standalone）&lt;/strong> 不依附任何檔案，從 &lt;code>script.google.com&lt;/code> 直接建立。它適合「不特別綁一個檔案」的工具，或要跨多個檔案操作的情境；存取試算表要用 &lt;code>SpreadsheetApp.openById(&amp;quot;表的ID&amp;quot;)&lt;/code> 明確指定。&lt;/p>
&lt;p>選擇判準很直接：&lt;strong>這段程式主要就是服務某一個檔案嗎&lt;/strong>——是（流量統計服務那張 log 表），用容器綁定；否（一個要操作很多表的通用工具），用獨立專案。&lt;/p>
&lt;h2 id="用到的服務">用到的服務&lt;/h2>
&lt;p>Apps Script 透過一組內建服務物件操作 Google 資源，這個案例會碰到的主要是：&lt;/p>
&lt;ul>
&lt;li>&lt;code>SpreadsheetApp&lt;/code>：讀寫試算表，&lt;code>appendRow&lt;/code>、&lt;code>getRange&lt;/code> 等，是資料的儲存層（模組三詳談）。&lt;/li>
&lt;li>&lt;code>ContentService&lt;/code>：產生 web app 的回應內容，&lt;code>doPost&lt;/code> 必須回傳它的輸出。&lt;/li>
&lt;li>&lt;code>ScriptApp&lt;/code>：管理觸發器，時間排程彙總會用到（模組四）。&lt;/li>
&lt;li>&lt;code>PropertiesService&lt;/code>：存少量 key-value 設定或狀態，適合放「上次處理到哪一列」這種跨執行要記住的小資料。&lt;/li>
&lt;/ul>
&lt;p>這些服務都以你的 Google 帳號身分執行、受你的授權範圍約束，授權模型是下一篇&lt;a href="https://tarrragon.github.io/blog/automation/01-apps-script-basics/web-app-deployment-model/" data-link-title="web app 部署模型與授權" data-link-desc="把 Apps Script 掛成可被 HTTP 呼叫的端點時，doGet/doPost 進入點、exec 與 dev 兩種網址、以及更新部署為什麼要用同一個網址">web app 部署模型&lt;/a>的主題。&lt;/p>
&lt;h2 id="下一步">下一步&lt;/h2>
&lt;p>知道 Apps Script 是什麼之後，要讓它能被 blog 的 beacon 打到，得把它部署成有公開網址的 web app。部署模型、&lt;code>doGet&lt;/code>/&lt;code>doPost&lt;/code>、以及授權流程，見&lt;a href="https://tarrragon.github.io/blog/automation/01-apps-script-basics/web-app-deployment-model/" data-link-title="web app 部署模型與授權" data-link-desc="把 Apps Script 掛成可被 HTTP 呼叫的端點時，doGet/doPost 進入點、exec 與 dev 兩種網址、以及更新部署為什麼要用同一個網址">web app 部署模型&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>Apps Script 是 Google 托管的 JavaScript 執行環境：你寫的程式碼跑在 Google 的伺服器上、用 V8 引擎執行，對個人 Google 帳號免費。它的定位是「膠水」——用少量程式碼把 Google 的服務（試算表、Gmail、日曆、雲端硬碟）跟外部串起來，補上這些服務單靠介面做不到的自動化。對流量統計這個案例，它扮演的是接住 beacon、把資料寫進 Sheet 的接收端。</p>
<h2 id="沒有常駐程序跟一般伺服器最大的差別">沒有常駐程序：跟一般伺服器最大的差別</h2>
<p>Apps Script 跟一台伺服器最根本的差別是<strong>沒有一個常駐、屬於你的程序</strong>。一般伺服器是一支持續執行的程式，開機後一直在記憶體裡等請求；Apps Script 的程式碼平時不執行，只在被觸發（有人打 web app 網址、觸發器到點、你手動按執行）時才啟動一個執行實例，跑完就結束。這個模型帶來幾個要先知道的取捨：</p>
<ul>
<li><strong>不必管主機</strong>：沒有作業系統要維護、沒有開關機、沒有閒置費用。程式碼不跑時完全不佔資源。</li>
<li><strong>每次執行是獨立的</strong>：兩次執行之間，記憶體裡的變數不會保留。要跨執行記住東西，得寫進外部儲存（Sheet、<code>PropertiesService</code>、Drive）。這跟伺服器可以用行程內記憶體 cache 是相反的。</li>
<li><strong>有執行上限</strong>：單次執行最長 6 分鐘、同時併發有數量限制。長時間或高併發的工作不適合，細節見<a href="/blog/automation/knowledge-cards/execution-quota/" data-link-title="Execution Quota（執行配額）" data-link-desc="Apps Script 個人帳號的執行時間、同時併發與觸發器每日總時間上限，決定免費膠水層能承受多大的量">執行配額</a>。</li>
</ul>
<p>理解「沒有常駐程序」才知道 Apps Script 適合什麼：短、偶發、由事件觸發的工作，例如「接一則 beacon 寫一列」「每天彙總一次」。不適合的是需要持續連線、低延遲、或狀態常駐記憶體的服務。</p>
<h2 id="容器綁定-vs-獨立專案">容器綁定 vs 獨立專案</h2>
<p>Apps Script 專案有兩種存在形式，差別在「它跟一個 Google 檔案綁不綁定」。</p>
<p><strong>容器綁定（container-bound）</strong> 的專案依附在一個具體檔案上——從某張試算表的 <code>擴充功能 → Apps Script</code> 開出來的專案，就綁定那張試算表。它的好處是程式裡用 <code>SpreadsheetApp.getActiveSpreadsheet()</code> 直接拿到那張表，不必記檔案 ID；流量統計用這種，程式跟資料表天生綁在一起，最省事。它也能存取容器檔案特有的事件（例如試算表的 <code>onEdit</code>、表單的 <code>onFormSubmit</code>）。</p>
<p><strong>獨立專案（standalone）</strong> 不依附任何檔案，從 <code>script.google.com</code> 直接建立。它適合「不特別綁一個檔案」的工具，或要跨多個檔案操作的情境；存取試算表要用 <code>SpreadsheetApp.openById(&quot;表的ID&quot;)</code> 明確指定。</p>
<p>選擇判準很直接：<strong>這段程式主要就是服務某一個檔案嗎</strong>——是（流量統計服務那張 log 表），用容器綁定；否（一個要操作很多表的通用工具），用獨立專案。</p>
<h2 id="用到的服務">用到的服務</h2>
<p>Apps Script 透過一組內建服務物件操作 Google 資源，這個案例會碰到的主要是：</p>
<ul>
<li><code>SpreadsheetApp</code>：讀寫試算表，<code>appendRow</code>、<code>getRange</code> 等，是資料的儲存層（模組三詳談）。</li>
<li><code>ContentService</code>：產生 web app 的回應內容，<code>doPost</code> 必須回傳它的輸出。</li>
<li><code>ScriptApp</code>：管理觸發器，時間排程彙總會用到（模組四）。</li>
<li><code>PropertiesService</code>：存少量 key-value 設定或狀態，適合放「上次處理到哪一列」這種跨執行要記住的小資料。</li>
</ul>
<p>這些服務都以你的 Google 帳號身分執行、受你的授權範圍約束，授權模型是下一篇<a href="/blog/automation/01-apps-script-basics/web-app-deployment-model/" data-link-title="web app 部署模型與授權" data-link-desc="把 Apps Script 掛成可被 HTTP 呼叫的端點時，doGet/doPost 進入點、exec 與 dev 兩種網址、以及更新部署為什麼要用同一個網址">web app 部署模型</a>的主題。</p>
<h2 id="下一步">下一步</h2>
<p>知道 Apps Script 是什麼之後，要讓它能被 blog 的 beacon 打到，得把它部署成有公開網址的 web app。部署模型、<code>doGet</code>/<code>doPost</code>、以及授權流程，見<a href="/blog/automation/01-apps-script-basics/web-app-deployment-model/" data-link-title="web app 部署模型與授權" data-link-desc="把 Apps Script 掛成可被 HTTP 呼叫的端點時，doGet/doPost 進入點、exec 與 dev 兩種網址、以及更新部署為什麼要用同一個網址">web app 部署模型</a>。</p>
]]></content:encoded></item><item><title>web app 部署模型與授權</title><link>https://tarrragon.github.io/blog/automation/01-apps-script-basics/web-app-deployment-model/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/automation/01-apps-script-basics/web-app-deployment-model/</guid><description>&lt;p>&lt;a href="https://tarrragon.github.io/blog/automation/knowledge-cards/web-app-deployment/" data-link-title="Web App Deployment（Web App 部署）" data-link-desc="把 Apps Script 專案掛成一個有公開網址、可被任何 HTTP 請求呼叫的端點時的部署模型與存取設定">web app 部署&lt;/a>是把 Apps Script 從「只能在編輯器裡手動執行」變成「有公開網址、任何 HTTP 請求都能觸發」的動作。這是讓 blog 的 beacon 能打到接收端的前提。這一篇講三件事：程式怎麼接住請求（&lt;code>doGet&lt;/code>/&lt;code>doPost&lt;/code>）、部署產生的兩種網址差在哪、以及授權為什麼第一次會跳警告。&lt;/p>
&lt;h2 id="doget-與-dopost兩個進入點">doGet 與 doPost：兩個進入點&lt;/h2>
&lt;p>web app 對外的行為由兩個特殊函式定義。收到 GET 請求時，Google 平台呼叫 &lt;code>doGet(e)&lt;/code>；收到 POST 請求時呼叫 &lt;code>doPost(e)&lt;/code>。參數 &lt;code>e&lt;/code> 帶著請求內容：&lt;code>doGet&lt;/code> 從 &lt;code>e.parameter&lt;/code> 拿 query string，&lt;code>doPost&lt;/code> 從 &lt;code>e.postData.contents&lt;/code> 拿請求主體。流量統計的 beacon 用 &lt;code>sendBeacon&lt;/code> 送 POST，所以接收端實作 &lt;code>doPost&lt;/code>，從 &lt;code>e.postData.contents&lt;/code> 讀那串 JSON 字串。&lt;/p>
&lt;p>兩個函式都必須回傳一個 &lt;code>ContentService&lt;/code> 或 &lt;code>HtmlService&lt;/code> 的輸出，這是平台的硬性要求——不回傳會被當成執行沒有正常結束。詳細用法見知識卡 &lt;a href="https://tarrragon.github.io/blog/automation/knowledge-cards/doget-dopost/" data-link-title="doGet / doPost" data-link-desc="Apps Script web app 的兩個進入點函式，分別接住 GET 與 POST 請求，決定端點收到請求時執行什麼">doGet / doPost&lt;/a>。&lt;/p>
&lt;p>值得先記住的一條限制是 Apps Script &lt;strong>沒有&lt;/strong> &lt;code>doOptions&lt;/code>，所以它無法回應跨網域請求的 CORS preflight。這條限制決定了前端 beacon 必須用不觸發 preflight 的方式送，是&lt;a href="https://tarrragon.github.io/blog/automation/02-analytics-beacon/frontend-beacon/" data-link-title="前端 beacon 與 CORS 障礙" data-link-desc="靜態站用瀏覽器送瀏覽事件到 Apps Script 時，為什麼要用 sendBeacon 送 text/plain 才不會被 CORS preflight 擋下">前端 beacon 與 CORS 障礙&lt;/a>的核心。&lt;/p>
&lt;h2 id="exec-與-dev兩種網址">exec 與 dev：兩種網址&lt;/h2>
&lt;p>部署 web app 後會遇到兩個結尾不同的網址，用途不一樣，搞混會在測試時卡住。&lt;/p>
&lt;p>&lt;code>/exec&lt;/code> 是&lt;strong>正式版網址&lt;/strong>：它對應你「部署」的那個版本、網址固定不變、遵守你設定的「誰可以存取」。blog 的 beacon 要填的是這個。&lt;code>/dev&lt;/code> 是&lt;strong>測試版網址&lt;/strong>：它永遠對應編輯器裡最新存檔的程式碼（不必重新部署就生效），但它只有對這個專案有編輯權的人（也就是你，登入狀態下）能存取。&lt;code>/dev&lt;/code> 適合你自己邊改邊測，&lt;code>/exec&lt;/code> 才是給匿名訪客用的。&lt;/p>
&lt;p>因為 &lt;code>/dev&lt;/code> 要登入、&lt;code>/exec&lt;/code> 才允許匿名，用 &lt;code>/dev&lt;/code> 當 beacon 端點會讓所有沒登入的訪客都被擋掉——這是一個容易誤用的點。beacon 一律用 &lt;code>/exec&lt;/code>。&lt;/p>
&lt;h2 id="更新部署為什麼要用同一個網址">更新部署為什麼要用同一個網址&lt;/h2>
&lt;p>改完程式後怎麼讓 &lt;code>/exec&lt;/code> 反映新版本，是另一個容易出錯的地方。Apps Script 有兩個看起來都能「部署」的入口：&lt;code>新增部署作業&lt;/code> 會產生一個&lt;strong>全新的&lt;/strong> &lt;code>/exec&lt;/code> 網址；&lt;code>管理部署作業 → 編輯 → 版本選「新版本」&lt;/code> 則是把&lt;strong>既有部署&lt;/strong>更新到新程式碼、&lt;strong>網址不變&lt;/strong>。&lt;/p>
&lt;p>正確做法是後者：第一次用「新增部署作業」拿到網址、填進 blog；之後每次改程式，都用「管理部署作業」更新同一個部署。如果每次都「新增部署作業」，會不斷產生新網址，而 blog 裡填的還是舊網址、指向舊版本的程式，於是「我明明改了程式怎麼沒生效」。記住這條分工，就避開了這個常見的假故障。&lt;/p>
&lt;h2 id="首次授權與未驗證警告">首次授權與未驗證警告&lt;/h2>
&lt;p>第一次部署（或第一次執行會存取你資料的程式）時，Google 會要求授權，流程中會出現一個「Google 尚未驗證這個應用程式」的警告畫面。這個警告是正常的：它出現的原因是這支腳本是你自己寫的、沒有經過 Google 的應用程式審核，而不是因為程式有問題。走「進階 → 前往（專案名稱）」繼續、再「允許」授予它存取你試算表的權限，就完成授權。&lt;/p>
&lt;p>授權授予的範圍只涵蓋程式實際用到的服務（這個案例是那一張試算表），不會給到你其他的 Google 資料。之後這支 web app 以你的身分執行，能做的事就是 &lt;code>doPost&lt;/code> 裡寫的那些。&lt;/p>
&lt;h2 id="下一步">下一步&lt;/h2>
&lt;p>部署模型清楚後，就能把接收端實際做出來、部署、收到第一筆瀏覽——見&lt;a href="https://tarrragon.github.io/blog/automation/02-analytics-beacon/receiver-handler/" data-link-title="接收端 handler：寫進第一筆" data-link-desc="Apps Script 這端怎麼解析 text/plain 的 beacon、用伺服器時間補上時間戳、append 進 Sheet，並在部署後確認收到第一筆真實瀏覽">模組二：接收端 handler&lt;/a>。部署設定「誰可以存取」的安全含義，見&lt;a href="https://tarrragon.github.io/blog/automation/05-deploy-quota-security/" data-link-title="模組五：部署、配額與安全" data-link-desc="把匿名可存取的 beacon 接收端上線後，怎麼守住免費配額、擋掉濫用、保持資料乾淨、以及判斷何時該換更重的工具">模組五&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p><a href="/blog/automation/knowledge-cards/web-app-deployment/" data-link-title="Web App Deployment（Web App 部署）" data-link-desc="把 Apps Script 專案掛成一個有公開網址、可被任何 HTTP 請求呼叫的端點時的部署模型與存取設定">web app 部署</a>是把 Apps Script 從「只能在編輯器裡手動執行」變成「有公開網址、任何 HTTP 請求都能觸發」的動作。這是讓 blog 的 beacon 能打到接收端的前提。這一篇講三件事：程式怎麼接住請求（<code>doGet</code>/<code>doPost</code>）、部署產生的兩種網址差在哪、以及授權為什麼第一次會跳警告。</p>
<h2 id="doget-與-dopost兩個進入點">doGet 與 doPost：兩個進入點</h2>
<p>web app 對外的行為由兩個特殊函式定義。收到 GET 請求時，Google 平台呼叫 <code>doGet(e)</code>；收到 POST 請求時呼叫 <code>doPost(e)</code>。參數 <code>e</code> 帶著請求內容：<code>doGet</code> 從 <code>e.parameter</code> 拿 query string，<code>doPost</code> 從 <code>e.postData.contents</code> 拿請求主體。流量統計的 beacon 用 <code>sendBeacon</code> 送 POST，所以接收端實作 <code>doPost</code>，從 <code>e.postData.contents</code> 讀那串 JSON 字串。</p>
<p>兩個函式都必須回傳一個 <code>ContentService</code> 或 <code>HtmlService</code> 的輸出，這是平台的硬性要求——不回傳會被當成執行沒有正常結束。詳細用法見知識卡 <a href="/blog/automation/knowledge-cards/doget-dopost/" data-link-title="doGet / doPost" data-link-desc="Apps Script web app 的兩個進入點函式，分別接住 GET 與 POST 請求，決定端點收到請求時執行什麼">doGet / doPost</a>。</p>
<p>值得先記住的一條限制是 Apps Script <strong>沒有</strong> <code>doOptions</code>，所以它無法回應跨網域請求的 CORS preflight。這條限制決定了前端 beacon 必須用不觸發 preflight 的方式送，是<a href="/blog/automation/02-analytics-beacon/frontend-beacon/" data-link-title="前端 beacon 與 CORS 障礙" data-link-desc="靜態站用瀏覽器送瀏覽事件到 Apps Script 時，為什麼要用 sendBeacon 送 text/plain 才不會被 CORS preflight 擋下">前端 beacon 與 CORS 障礙</a>的核心。</p>
<h2 id="exec-與-dev兩種網址">exec 與 dev：兩種網址</h2>
<p>部署 web app 後會遇到兩個結尾不同的網址，用途不一樣，搞混會在測試時卡住。</p>
<p><code>/exec</code> 是<strong>正式版網址</strong>：它對應你「部署」的那個版本、網址固定不變、遵守你設定的「誰可以存取」。blog 的 beacon 要填的是這個。<code>/dev</code> 是<strong>測試版網址</strong>：它永遠對應編輯器裡最新存檔的程式碼（不必重新部署就生效），但它只有對這個專案有編輯權的人（也就是你，登入狀態下）能存取。<code>/dev</code> 適合你自己邊改邊測，<code>/exec</code> 才是給匿名訪客用的。</p>
<p>因為 <code>/dev</code> 要登入、<code>/exec</code> 才允許匿名，用 <code>/dev</code> 當 beacon 端點會讓所有沒登入的訪客都被擋掉——這是一個容易誤用的點。beacon 一律用 <code>/exec</code>。</p>
<h2 id="更新部署為什麼要用同一個網址">更新部署為什麼要用同一個網址</h2>
<p>改完程式後怎麼讓 <code>/exec</code> 反映新版本，是另一個容易出錯的地方。Apps Script 有兩個看起來都能「部署」的入口：<code>新增部署作業</code> 會產生一個<strong>全新的</strong> <code>/exec</code> 網址；<code>管理部署作業 → 編輯 → 版本選「新版本」</code> 則是把<strong>既有部署</strong>更新到新程式碼、<strong>網址不變</strong>。</p>
<p>正確做法是後者：第一次用「新增部署作業」拿到網址、填進 blog；之後每次改程式，都用「管理部署作業」更新同一個部署。如果每次都「新增部署作業」，會不斷產生新網址，而 blog 裡填的還是舊網址、指向舊版本的程式，於是「我明明改了程式怎麼沒生效」。記住這條分工，就避開了這個常見的假故障。</p>
<h2 id="首次授權與未驗證警告">首次授權與未驗證警告</h2>
<p>第一次部署（或第一次執行會存取你資料的程式）時，Google 會要求授權，流程中會出現一個「Google 尚未驗證這個應用程式」的警告畫面。這個警告是正常的：它出現的原因是這支腳本是你自己寫的、沒有經過 Google 的應用程式審核，而不是因為程式有問題。走「進階 → 前往（專案名稱）」繼續、再「允許」授予它存取你試算表的權限，就完成授權。</p>
<p>授權授予的範圍只涵蓋程式實際用到的服務（這個案例是那一張試算表），不會給到你其他的 Google 資料。之後這支 web app 以你的身分執行，能做的事就是 <code>doPost</code> 裡寫的那些。</p>
<h2 id="下一步">下一步</h2>
<p>部署模型清楚後，就能把接收端實際做出來、部署、收到第一筆瀏覽——見<a href="/blog/automation/02-analytics-beacon/receiver-handler/" data-link-title="接收端 handler：寫進第一筆" data-link-desc="Apps Script 這端怎麼解析 text/plain 的 beacon、用伺服器時間補上時間戳、append 進 Sheet，並在部署後確認收到第一筆真實瀏覽">模組二：接收端 handler</a>。部署設定「誰可以存取」的安全含義，見<a href="/blog/automation/05-deploy-quota-security/" data-link-title="模組五：部署、配額與安全" data-link-desc="把匿名可存取的 beacon 接收端上線後，怎麼守住免費配額、擋掉濫用、保持資料乾淨、以及判斷何時該換更重的工具">模組五</a>。</p>
]]></content:encoded></item></channel></rss>