Google 的 Apps Script 是個很不錯的服務,很方便就可以建立後端應用,不過如果回應純文字內容,就會因為安全考量而改用轉址方式傳回真正的文字。底下以我所撰寫從 Yahoo 股市新聞擷取新聞標題與摘要的簡易服務為例說明,這個服務可以透過網址尾端的查詢字串加入兩個參數:

參數名稱 用途
topic 必要參數,傳入 "news" 表示擷取標題,會用 JSON 陣列傳回標題字串;傳入 "news_detail" 則是擷取標題與摘要,會以 JSON 陣列傳回物件,每個物件內含 titledescription 屬性記錄標題與摘要
num 新聞筆數,如果沒有指定,預設為 10 筆

使用 curl 觀察

我們可以最方便的 curl 工具觀察:

curl -i "https://script.google.com/macros/s/AKfycbyA8mGQqVpc9CLd3FH0Zp8Vp9zpCfNpS2HeK99YW3kiAJEc8d_oRBZlFjTn9bx1L5Cl/exec?topic=news&num=1"

結果如下:

HTTP/2 302 
content-type: text/html; charset=UTF-8
access-control-allow-origin: *
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Sat, 12 Apr 2025 02:53:14 GMT
location: https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLjVgOxSMUs1O_P0daWDd58ucki0Mg0mvSceJNN0RIM7k6iriCi_Sy1nsu8Jc5JIK-xmpxBekGXJ-_W-KG0ps9cs7PUclTP5eBBtmIeP18UUe5T4R0Oc6q15d4vG2H4w6gtBVTe4UMlbmURZyx8w3j2MfB1PsSc77QSCNqnKZ5zFlyjnxI-1tybILXgpeTuvYCR01iMcTCwNJUcPdk78aQ3IX3feeKO4Co9bZf8nfTu6ytuy849A3rin6m6Bw_n4Rwj5as8NacK-pOwECGvW2Ixei7xpT3wZIvWlS8_BzqmlvMvcblQ8AfjNIplpcA&lib=M1YLor6O1PntGCCrJMyICgDA3Wcg5FMSu
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self'
x-xss-protection: 1; mode=block
server: GSE
accept-ranges: none
vary: Accept-Encoding



Moved Temporarily



Moved Temporarily
The document has moved here.





    Enter fullscreen mode
    


    Exit fullscreen mode
    




可以看到回應 302 狀態碼,表示網頁已搬移,並且在 Location 表頭以及回覆內容中都有註明搬遷的新網址。如果使用 -L 讓 curl 跟隨新網址轉址,就可以取得真正的結果:

curl -i -L "https://script.google.com/macros/s/AKfycbyA8mGQqVpc9CLd3FH0Zp8Vp9zpCfNpS2HeK99YW3kiAJEc8d_oRBZlFjTn9bx1L5Cl/exec?topic=news&num=1"



    Enter fullscreen mode
    


    Exit fullscreen mode
    




結果如下:

HTTP/2 302 
content-type: text/html; charset=UTF-8
access-control-allow-origin: *
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Sat, 12 Apr 2025 02:08:29 GMT
location: https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLi-hIwVxJfg-121RHpjMNfukz0wd_LqlUr-40Apl6eH_OUdonYOgNBLsXm_ezL3MeCDFYMm5dytM7a1BVmlaX732wWiVAe6bBXdU6WugzbewnenV7K-sjspO_-oxcKzzcQhomudwC9GKrrixSMBlU5CLQG6wIgziidspL_ayDaSZfekw_Lqexodg0yz7E829G8RyY5KOhGxfgWDmorATU5aZs2Cflv-mpDFE_WhNfPzlc_-sA8e2OoCo05T5Xxe46T33xk6BB7zjZTlpQ-UXPDf0veLLjY46-fF58nD85dEjG8I8oNize4mLkNKCA&lib=M1YLor6O1PntGCCrJMyICgDA3Wcg5FMSu
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self'
x-xss-protection: 1; mode=block
server: GSE
accept-ranges: none
vary: Accept-Encoding

HTTP/2 200 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
access-control-allow-origin: *
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Sat, 12 Apr 2025 02:08:29 GMT
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self'
x-xss-protection: 1; mode=block
server: GSE
accept-ranges: none
vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site,Accept-Encoding

["外資回補305億今年次多 大盤周跌1769點"]



    Enter fullscreen mode
    


    Exit fullscreen mode
    




你可以清楚看到第一次得到回覆 302 後,就接著連網新網址,因此得到回覆 200,並取得新聞標題。
  
  
  Apps Script 的轉址還有時間限制
要注意的是,Apps Script 的轉址設定有時間限制,如果沒有立刻連往新網址,這個新網址也會失效(目前沒有找到正式的官方文件明確表示限制時間的長度,我自己實測是 30 秒)。底下以 Python 示範:

import requests
url = 'https://script.google.com/macros/s/AKfycbyA8mGQqVpc9CLd3FH0Zp8Vp9zpCfNpS2HeK99YW3kiAJEc8d_oRBZlFjTn9bx1L5Cl/exec?topic=news&num=1'



    Enter fullscreen mode
    


    Exit fullscreen mode
    




首先利用 requests.get 並停用自動轉址:

r = requests.get(
    url,
    allow_redirects=False
)
print(r.status_code)
print(r.headers["Location"])



    Enter fullscreen mode
    


    Exit fullscreen mode
    




可以得到如下的結果

302
https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLilc0B7RGQPA7hqmbrSW9XYGSWu6ldPdTL0LzR70fXtlNd5WBi0m8eYWV0E70eJkztTRwFZfoTFlxyDN0VLqhk_eqsxw9y57-mMXmcZ9XQQpetX4pC-fHAmisEuVUT929XMcUtDq3FNqRuyUhLFVdJbNv2RgDQWSLLYNDixCjTqPcdv0rGUHmQgAotkeKHP0aCptNGJTnYAQdxMnwXB_-uu7n2K3yUNknQsqGniZJQiUYKDmrfXwksGmf2M4v0o9RyYYM_ur0vn3o853l4dp4iTbM3QkDxp47s7tKq-ExT99rdD_tcxdGF46ZcnYA&lib=M1YLor6O1PntGCCrJMyICgDA3Wcg5FMSu



    Enter fullscreen mode
    


    Exit fullscreen mode
    




如同剛剛使用 curl 觀察到的結果,並可以取得搬移後的新網址,如果沒有立刻循該網址連接過去,而是過了一段時間才連接:

r = requests.get(
    r.headers["Location"],
    allow_redirects=False
)

print(r.status_code)
print(r.text)



    Enter fullscreen mode
    


    Exit fullscreen mode
    




就會再次得到 302 回覆:

302
https://script.google.com/macros/s/AKfycbyA8mGQqVpc9CLd3FH0Zp8Vp9zpCfNpS2HeK99YW3kiAJEc8d_oRBZlFjTn9bx1L5Cl/exec?topic=news&num=1



    Enter fullscreen mode
    


    Exit fullscreen mode
    




如果你注意看,會發現它又轉回最原本的網址,所以如果繼續循這個新網址,就會再重複剛剛的轉址流程了。如果在適當的時間內連接新網址,就可以取得正確結果:

r = requests.get(
    url,
    allow_redirects=False
)

r = requests.get(
    r.headers["Location"],
    allow_redirects=False
)

print(r.status_code)
print(r.text)



    Enter fullscreen mode
    


    Exit fullscreen mode
    




結果如下:

200
["外資回補305億今年次多 大盤周跌1769點"]



    Enter fullscreen mode
    


    Exit fullscreen mode
    




如果要透過程式取用使用 Apps Script 架設的服務或是 API,就要記得處理轉址。舉例來說,在較早版本的 MicroPython 韌體中,它的 urequests 模組就沒有自動轉址的功能,可參考〈讓 MicroPython 的 urequests 模組支援 redirection〉一文。
  
  
  Apps Script 是轉址到不同的主機(host)
另外,要注意的是,Apps Script 服務的網址是:

https://script.google.com/....



    Enter fullscreen mode
    


    Exit fullscreen mode
    




但是轉址後的網址是:

https://script.googleusercontent.com/...



    Enter fullscreen mode
    


    Exit fullscreen mode
    




兩者的主機(Host)名稱不同,有些程式庫在轉址時會沿用原本網址的主機名稱,就會造成問題,例如若我們強制這樣處理:

r = requests.get(
    url,
    allow_redirects=False
)

r = requests.get(
    r.headers["Location"],
    headers={
        "Host": "script.google.com"
    },
    allow_redirects=False
)

print(r.status_code)
print(r.text)



    Enter fullscreen mode
    


    Exit fullscreen mode
    




就會因為在錯誤的主機上找不到對應的路徑而得到 404 回覆:

404
Page Not Found.goog-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}#drive-logo{margin:18px 0;position:absolute;white-space:nowrap}.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png);-webkit-background-size:116px 41px;background-size:116px 41px;display:inline-block;height:41px;vertical-align:bottom;width:116px}.docs-drivelogo-text{color:#000;display:inline-block;opacity:.54;text-decoration:none;font-family:"Product Sans",Arial,Helvetica,sans-serif;font-size:32px;text-rendering:optimizeLegibility;position:relative;top:-6px;left:-7px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (-webkit-min-device-pixel-ratio:1.5),(min-resolution:144dpi){.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_116x41dp.png)}}sentinel{}body {background-color: #fff; font-family: Arial,sans-serif; font-size: 13px; margin: 0; padding: 0;}a, a:link, a:visited {color: #112ABB;}.errorMessage {font-size: 12pt; font-weight: bold; line-height: 150%;} DriveSorry, unable to open the file at this time. Please check the address and try again. Get stuff done with Google DriveApps in Google Drive make it easy to create, store and share online documents, spreadsheets, presentations and more.Learn more at drive.google.com/start/apps.html {height: 100%; overflow: auto;}body {height: 100%; overflow: auto;}#outerContainer {margin: auto; max-width: 750px;}#innerContainer {margin-bottom: 20px; margin-left: 40px; margin-right: 40px; margin-top: 80px; position: relative;}



    Enter fullscreen mode
    


    Exit fullscreen mode
    




這個問題在 MicroPython 1.24 的 requests 會出現,可參考〈MicroPython 1.24.0 的 requests 重新導向的問題〉一文,我已經提出 PR 修正,應該在之後的版本就會更新了。