經過前面的測試已驗證了重構後的程式碼基本上達成了讓平台具備 API Key 功能的目標, 在提交到 GitHub 之前, 想要先佈署到 Mapleboard 上更新 serverless 到具有 API Key 功能的最新版. 關於 Mapleboard 筆記參考 :
7. 在 Mapleboard 佈署新版 serverless :
先用 VNC Cloud 遠端連線到 Mapleboard 桌面, 開啟終端機, 切換到 serverless 專案目錄下, 用 zip 指令把整個專案除指定之敏感檔案外全部壓縮成 zip 檔 :
tony1966@LX2438:~/flask_apps/serverless$ zip -r serverless_v4.zip . -x "serverless.db" "serverless_error.log" "*.pyc" "__pycache__/*" ".env"
參數 -r 表示要遞迴壓縮, 即連同所有子資料夾 (如 functions/) 一起打包. serverless_backup.zip 是壓縮結果的檔檔名. 後面的 . . 代表壓縮當前目錄下的所有東西, -x 參數後面接的是排除 (不壓縮) 名單, 這裡排除了本地資料庫 (serverless.db), 日誌檔 (serverless_error.log), Python 快取檔, 以及含有敏感密碼的 .env 檔.
然後用 WinSCP 連線 Mapleboard, 注意, 之前安裝 fail2ban 時為了提升資安, 已修改 SSH 埠 (不再是預設的 22), 埠號可用下列指令查得 :
tony1966@LX2438:~/flask_apps/serverless$ sudo nano /etc/fail2ban/jail.local
設定 WinSCP 連線時除了要輸入固定 IP 外, 還要更改 SSH 埠號, 如果用 22 埠是無法連線的. 連線成功後, 先將上面備份的 zip 檔傳送至本地保存. 完成後將本地的 serverless.py 主程式與 functions 資料夾上傳到 Mapleboard 的 serverless 專案目錄下覆蓋舊版程式檔.
由於主程式 serverless.py 有更改, 所以須用下例指令重啟服務才會運行新版程式 :
tony1966@LX2438:~/flask_apps/serverless$ sudo systemctl restart serverless
用瀏覽器測試 hello.py 函式 :
在有登入情況下, 對函式的請求無需攜帶 API Key 即可順利執行; 如果沒有登入就會收到 401 錯誤, 例如 :
但修改前一篇的 deploy.py 的 URL 想要進行本地佈署 hello.py 卻出現連線異常與 404 等錯誤, 經查原來我的 Mapleboard 之前在架站時 Nginx 與站台 (主要是 hello 站台與 flask.tony1966.cc) 設定出現埠的衝突, 重啟 Nginx 出現 2~3 個 warning. 經過與 Gemini 討論後, 修改站台設定後終於解決此問題, Nginx 設定檔就徹底理順了, 摘要如下 :
- reject_ip 盡職地守在大門口擋掉所有奇奇怪怪的 IP 掃描.
- flask.tony1966.cc 安全地走 HTTPS 連線, 讓新版 Serverless 平台, 樹莓派爬蟲與電腦部署都能順暢通訊.
- hello 站台也成功轉型, 乾乾淨淨地留在 443 埠當作你的 is_alive 測試通道 (Port 8080/8081).
站台清單檢視指令 : ls -l /etc/nginx/sites-enabled/
重啟 Nginx 伺服器指令 : sudo nginx -t
重新載入 Nginx 指令 : sudo systemctl reload nginx
佈署程式 deploy.py 的 URL 要改成 https://flask.tony1966.cc, 下面是佈署市圖爬蟲伺服端程式 update_ksml_books.py 的範例 (伺服端程式都不必為 serverless 升版做任何改變) :
SERVER_URL="https://flask.tony1966.cc"
API_TOKEN="your-api-key"
# 2. 定義要佈署的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="update_ksml_books"
LOCAL_FILE_PATH="update_ksml_books.py"
再次執行 deploy.py 就順利將函式發佈到 serverless 平台上了 :
D:\python\test>python deploy.py
🚀 正在將 update_ksml_books.py 更新至 https://flask.tony1966.cc...
✅ 函式更新成功!
伺服器回應: {'func_name': 'update_ksml_books', 'message': '模組 update_ksml_books 已成功更新'}
deploy.py 的完整內容如下 :
# deploy.py
import os
import requests
# 1. 設定伺服器資訊與 API Token
# 地端測試可用 http://127.0.0.1:5000,上雲端後改成你的 Render 網址
SERVER_URL="https://flask.tony1966.cc"
API_TOKEN="your-api-key"
# 2. 定義要佈署的函式名稱與本地檔案路徑
TARGET_FUNCTION_NAME="update_ksml_books"
LOCAL_FILE_PATH="update_ksml_books.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()
市圖爬蟲程式本機版則需要配合 serverless 添加 API Key 功能而升版, 否則請求都會被 401 拒絕, 這部分記在另一篇.