第一版的 serverless 系統在新增或修改函式時都需登入平台, 透過手動操作網頁來完成, 在本次重構加上 API Key 機制後, 系統安全性增強, 可以在本地撰寫一個自動化佈署程式, 攜帶 API Key 經過驗證完成函式的佈署. 只要寫一個 Python 函式讀取要佈署的函式檔, 然後攜帶 API key 呼叫 update_function 或 save_function 即可完成函式的佈署.
> 我執行下列佈署程式 :
# deploy.py
import os
import requests
# 1. 設定伺服器資訊與 API Token
# 地端測試可用 http://127.0.0.1:5000,上雲端後改成你的 Render 網址
SERVER_URL="http://127.0.0.1:5000"
API_TOKEN="new-test-token"
# 2. 定義要更新的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="hello"
LOCAL_FILE_PATH="hello.py"
def deploy_function():
# 檢查本地檔案是否存在
if not os.path.exists(LOCAL_FILE_PATH):
print(f"❌ 找不到本地檔案: {LOCAL_FILE_PATH}")
return
# 讀取本地最新的程式碼內容
with open(LOCAL_FILE_PATH, "r", encoding="utf-8") as f:
new_code=f.read()
# 3. 準備發送給 update_function 的端點與資料
# 路由設計是動態載入的 /function/update_function
url=f"{SERVER_URL}/function/update_function"
headers={
"X-API-Key": API_TOKEN,
"Content-Type": "application/json"
}
payload={
"func_name": TARGET_FUNCTION_NAME,
"code": new_code
}
print(f"🚀 正在將 {LOCAL_FILE_PATH} 部署至 {SERVER_URL}...")
try:
# 發送 POST 請求更新遠端函式
response=requests.post(url, json=payload, headers=headers)
# 檢查伺服器回應狀態
if response.status_code == 200:
print("✅ 函式更新成功!")
print("伺服器回應:", response.json())
else:
print(f"❌ 更新失敗 (狀態碼: {response.status_code})")
try:
print("錯誤原因:", response.json())
except ValueError:
print("非 JSON 回應內容:", response.text)
except requests.exceptions.RequestException as e:
print(f"💥 連線發生異常: {e}")
deploy_function()
===
出現如下錯誤 :
D:\python\test>python deploy.py
🚀 正在將 hello.py 部署至 http://127.0.0.1:5000...
❌ 更新失敗 (狀態碼: 401)
錯誤原因: {'error': 'Authentication required', 'login_url': '/login'}
===
在提供有效 API Key 情況下應該要能通過不受 login 阻攔, 請修改
▸ Thought for 29s
The user is experiencing a 401 error with the message "Authentication required" ...
問題很清楚。看一下目前的驗證順序:
● Read(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
根本原因找到了:
步驟 1(L165)先攔截, update_function 在 PROTECTED_FUNCTIONS 裡,API Client 沒有 Session →
直接 401,根本輪不到步驟 2 的 Token 驗證。
解法:將兩層驗證合併,一次判斷 Session 或 Token 擇一通過,同時可以移除 TOKEN_PROTECTED_FUNCTIONS
(已不需要):
● Read(D:/antigravity_cli/projects/serverless/serverless.py)
if __name__ == "__main__":
● Edit(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
完成。來驗證最終結果:
● Read(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
還有一個小問題:L184 的步驟編號 # 3. 與 L182 的 # 3. 重複了,順手修正:
● Edit(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
完成。以下是這次修改的完整說明:
──────
## 問題根源
原本流程(有 Bug):
步驟 1:update_function 在 PROTECTED_FUNCTIONS? → 是
check_auth() = False(API Client 無 Session)
→ 直接 401 ❌ (Token 驗證根本輪不到)
## 修正後的流程
新流程(handle_function 前三步):
步驟 1:一次性完成雙重驗證
is_session_auth = check_auth()
if 無 Session → 嘗試讀 X-API-Key → 查資料庫 → is_token_auth
is_authorized = is_session_auth OR is_token_auth
步驟 2:管理模組 → 需要 is_authorized,否則 401
步驟 3:一般函式 → 需要 is_authorized,否則 401
## 各情境結果
呼叫者 | Session | API Key | 結果
-----------------------------|----------------------|----------------------|----------------------
瀏覽器管理者(update/save) | ✅ | ❌ | ✅ 放行
deploy.py API Client | ❌ | ✅ 有效 | ✅ 放行
未認證請求 | ❌ | ❌ | ❌ 401
無效 Token | ❌ | ❌ 無效 | ❌ 401
────────────────────────────────────────────────────────────
> 成功了, 但出現連線異常:
D:\python\test>python deploy.py
🚀 正在將 hello.py 部署至 http://127.0.0.1:5000...
✅ 函式更新成功!
💥 連線發生異常: Expecting value: line 1 column 1 (char 0)
這要修改 deploy.py 還是系統的 update_function.py 較好?
▸ Thought for 27s
The user is seeing a successful update (✅) but then a connection error. Let me...
先看清楚錯誤發生在哪一行:
deploy.py 收到 200 → 印出 ✅ → 再執行 response.json() 時爆炸,代表 update_function.py
回傳的是 HTML 而非 JSON。
讓我確認 update_function.py 的完整內容:
● Read(D:/antigravity_cli/projects/serverless/functions/update_function.py) (ctrl+o to expand)
問題找到了,而且有兩個 bug 同時存在:
# | 問題 | 說明
---|--------------|-------------------------------------------------------------------------------
1 | 欄位名稱不符 | deploy.py 送 func_name ,但 update_function.py 讀 module_name →
| | 讀到空字串
2 | 輸入格式不符 | deploy.py 送 JSON body,但 update_function.py 只讀 request.form →
| | 永遠讀不到資料
3 | 回應格式不符 | 成功時回傳 HTML, deploy.py 呼叫 response.json() 爆炸
──────
## 修哪個?
修 update_function.py ,理由:
• 這是 server 端的問題(不認識 JSON 輸入、不回傳 JSON)
• 瀏覽器用表單呼叫、API Client 用 JSON 呼叫,server 應該兩者都支援
• deploy.py 的設計是正確的,不需要改
● Edit(D:/antigravity_cli/projects/serverless/functions/update_function.py)
● Create(D:/antigravity_cli/projects/serverless/functions/update_function.py) (ctrl+o to expand)
完成。以下是修改摘要:
──────
## 修改的檔案
### update_function.py
修正了三個問題:
# | 問題 | 修正方式
---|--------------------------------------|-------------------------------------------------------
1 | 只讀 request.form ,不懂 JSON | 用 request.is_json 判斷,JSON 時改讀
| | request.get_json()
2 | 只認 module_name ,不認 func_name | JSON 輸入時同時嘗試讀取 func_name 與 module_name
3 | 成功時只回傳 HTML | JSON 請求時回傳 {"message": "...", "func_name":
| | "..."}
──────
## 預期執行結果
D:\python\test>python deploy.py
🚀 正在將 hello.py 部署至 http://127.0.0.1:5000...
✅ 函式更新成功!
伺服器回應: {'func_name': 'hello', 'message': '模組 hello 已成功更新'}
────────────────────────────────────────────────────────────
> update_function 是更新已有的函式, 如果要新增函式則是使用 add_function 與 save_function,
如果要佈署新函式, deploy.py 要怎麼改? 同時請分析 add_function.py 與 save_function.py 在執行 deploy.p
佈署方面是否有需要配合修改之處?
▸ Thought for 1s
The user wants to understand the deployment flow for new functions. Let me first...
先讀取三個相關檔案:
● Read(D:/antigravity_cli/projects/serverless/functions/add_function.py)
● Read(D:/antigravity_cli/projects/serverless/functions/save_function.py) (ctrl+o to expand)
分析完畢。以下是完整報告:
──────
## 架構釐清
add_function → 純 UI 頁面,回傳 HTML 表單,action 指向 save_function
save_function → 實際寫檔(新增),只接受 form POST
update_function → 實際寫檔(覆蓋),已修改支援 JSON
deploy.py 要新增函式,只需呼叫 save_function ,不需碰 add_function (那是給瀏覽器用的 UI)。
──────
## save_function.py 的問題(與 update_function 一樣)
# | 問題 | 影響
-----------------------------|--------------------------------------|-----------------------------
1 | 只讀 request.form ,不懂 JSON | API Client 送來的資料讀不到
2 | 只認 module_name ,不認 func_name | deploy.py 欄位名稱不符
3 | 成功/失敗都回傳 HTML | response.json() 會爆炸
──────
## 修改計劃
修改 save_function.py :與 update_function.py 相同邏輯,支援 JSON/form 雙輸入。
修改 deploy.py :加入「新增 or 更新」判斷邏輯,自動選擇呼叫 save_function 或 update_function
。
開始修改:
● Create(D:/antigravity_cli/projects/serverless/functions/save_function.py) (ctrl+o to expand)
現在修改 deploy.py ,加入自動判斷新增或更新:
● Create(D:/python/test/deploy.py) (ctrl+o to expand)
完成。以下是完整摘要:
──────
## 修改了哪些檔案
檔案 | 修改內容
--------------------------------|-----------------------------------------------------------------
save_function.py | 支援 JSON/form 雙輸入、相容 func_name / module_name 、回傳
| JSON(201)或 HTML
deploy.py | 新增 function_exists() 探測,自動選 save_function 或
| update_function
functions/update_function.py | 上一輪已修改,本次不動
add_function.py | 不需修改,它只是瀏覽器 UI 頁面
──────
## deploy.py 新流程
執行 deploy.py
↓
function_exists():GET /function/{func_name}
├─ 404 → 函式不存在 → POST /function/save_function → 回 201 ✅
└─ 其他 → 函式已存在 → POST /function/update_function → 回 200 ✅
──────
## 預期執行結果
# 第一次佈署(函式不存在)
🚀 正在將 hello.py 新增至 http://127.0.0.1:5000...
✅ 函式新增成功!
伺服器回應: {'func_name': 'hello', 'message': '模組 hello 已成功建立'}
# 第二次佈署(函式已存在)
🚀 正在將 hello.py 更新至 http://127.0.0.1:5000...
✅ 函式更新成功!
伺服器回應: {'func_name': 'hello', 'message': '模組 hello 已成功更新'}
上面程序中 Claude 已經修改 serverless.py, update_function.py, 以及 save_function.py, 且修正了原先使用的佈署程式 deploy.py. 接下來要實測看看是否可在本機用佈署程式 deploy.py 將 hello.py 發布到後端平台上.
# deploy.py
import os
import requests
# 1. 設定伺服器資訊與 API Token
# 地端測試可用 http://127.0.0.1:5000,上雲端後改成你的 Render 網址
SERVER_URL="http://127.0.0.1:5000"
API_TOKEN="new-test-token"
# 2. 定義要佈署的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="hello"
LOCAL_FILE_PATH="hello.py"
def function_exists(func_name):
"""檢查遠端伺服器上的函式是否已存在(透過 GET 探測)"""
url=f"{SERVER_URL}/function/{func_name}"
headers={"X-API-Key": API_TOKEN}
try:
response=requests.get(url, headers=headers)
# 404 表示不存在,其他狀態(200/400/500)表示檔案存在
return response.status_code != 404
except requests.exceptions.RequestException:
return False # 連線失敗時保守假設不存在
def deploy_function():
# 檢查本地檔案是否存在
if not os.path.exists(LOCAL_FILE_PATH):
print(f"❌ 找不到本地檔案: {LOCAL_FILE_PATH}")
return
# 讀取本地最新的程式碼內容
with open(LOCAL_FILE_PATH, "r", encoding="utf-8") as f:
new_code=f.read()
headers={
"X-API-Key": API_TOKEN,
"Content-Type": "application/json"
}
payload={
"func_name": TARGET_FUNCTION_NAME,
"code": new_code
}
# 3. 自動判斷:函式已存在 → update,不存在 → save(新增)
if function_exists(TARGET_FUNCTION_NAME):
url=f"{SERVER_URL}/function/update_function"
action="更新"
else:
url=f"{SERVER_URL}/function/save_function"
action="新增"
print(f"🚀 正在將 {LOCAL_FILE_PATH} {action}至 {SERVER_URL}...")
try:
response=requests.post(url, json=payload, headers=headers)
# 新增成功是 201,更新成功是 200
if response.status_code in (200, 201):
print(f"✅ 函式{action}成功!")
print("伺服器回應:", response.json())
else:
print(f"❌ {action}失敗 (狀態碼: {response.status_code})")
try:
print("錯誤原因:", response.json())
except ValueError:
print("非 JSON 回應內容:", response.text)
except requests.exceptions.RequestException as e:
print(f"💥 連線發生異常: {e}")
if __name__ == "__main__":
deploy_function()
可見 Claude 修改後的 deploy.py 是透過讀取 functions 資料夾下有無該函式來判斷是要新增 (無) 還是更新 (有), 目前 functions 下有 hello.py, 所以執行