<?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>Doget-Dopost on Tarragon</title><link>https://tarrragon.github.io/blog/tags/doget-dopost/</link><description>Recent content in Doget-Dopost 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/tags/doget-dopost/index.xml" rel="self" type="application/rss+xml"/><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>