cloudflare-worker-notes — docs/NOTES.md — shell preview

cat docs/NOTES.md

入門筆記(給 20 年前 LAMP 老手)

這份筆記也會放進 repo 的 docs/NOTES.md。把你以前用過的東西當作錨點,比看 Cloudflare 文件快。

心智模型對照表

你以前熟的 現在的對應 差異
Apache + mod_php(document root 放 .php,request 進來 Apache 交給 PHP 執行) Cloudflare Workers(你寫一個 fetch(request) 函式,Cloudflare runtime 把請求餵給它) 沒有 document root,只有一個函式。沒有「靜態檔」概念,靜態東西要嘛放 R2、要嘛用 Workers Sites/Pages。
httpd.conf / Vhost / .htaccess wrangler.toml TOML 格式設定檔,描述 Worker 名字、要綁哪個 D1/R2、cron 何時跑。
重啟 apache systemctl restart apache wrangler deploy 推上 Cloudflare 全球邊緣節點,幾秒內所有節點上線。
tail -f /var/log/apache2/error.log wrangler tail 即時看 Worker 的 console.log + 錯誤;可以另開 terminal 整天掛著。
shared hosting cron / crontab -e Cron Triggers(wrangler.tomlcrons = [...] 一樣的 cron 語法 分 時 日 月 週,但時區是 UTC。Worker 收到 cron 時呼叫 scheduled() 那個 export。
MySQL + mysql_query() / PDO D1 + env.DB.prepare("SELECT ...").bind(?).all() 後端引擎是 SQLite(不是 MySQL,但 SQL 90% 相通)。寫法用 prepared statement + .bind(),跟 PDO 概念一樣。
/var/www/uploadsmove_uploaded_file() 存使用者上傳 R2env.BUCKET.put("key", data) / env.BUCKET.get("key") 沒有「目錄/檔名」結構,本質是 key-value:你愛取什麼 key 就取什麼(用 / 分隔只是視覺習慣)。介面跟 AWS S3 一模一樣。
$_SESSION / 寫到 /tmp 沒有對應——Workers 沒有跨請求的本地記憶 需要跨請求保留的東西一律寫 D1 / KV / R2。Workers 跑完函式記憶體就清掉。
.env + getenv() wrangler secret put NAME 設值,程式碼裡 env.NAME 本機開發另放 .dev.vars 檔(KEY=VALUE 一行一個),記得進 .gitignore
HTTPS / Let's Encrypt 自己設 自動 <name>.workers.dev 直接是 https,沒得選。
Composer 拉套件 npm install <pkg> JS 生態的套件管理器,跟 Composer 概念一樣,把相依寫進 package.jsondependencies 區塊。
PHP 直譯執行 TypeScript → 編譯 → JS(wrangler 自動做) TS 就是 JS 加型別註解,編譯後跑的還是 JS。寫法跟你以前的 traditional JS 90% 相通,多了 : string: number 之類的標註。不寫型別也能跑,但 IDE 抓不到錯。

Workers 的執行模型(一張圖看懂)

LINE 送來 HTTP POST /webhook
  ↓
Cloudflare 邊緣節點(最近你的那個)
  ↓ 拉起一個 V8 isolate(毫秒級,超輕量)
  ↓ 把 Request 物件傳進你的 fetch() 函式
你的程式跑:fetch LINE API、寫 D1、傳 R2、回 Response
  ↓ 函式 return Response
  ↓ Cloudflare 把 Response 傳回 LINE
  ↓ isolate 可能保留也可能清掉,反正你不能依賴它的記憶體

跟 Apache + mod_php 的「每個 request 起一個 PHP 解譯器」很像,差別是 V8 isolate 比 PHP process 輕 1000 倍,全球各節點都跑得起來。

你會用到的 wrangler 指令清單

npm create cloudflare@latest family-bot
# 互動精靈,問你要 Worker 還是其他類型、JS/TS、要不要範例

cd family-bot
npm install                  # 跟 composer install 同義

wrangler login               # 開瀏覽器,用你 Cloudflare 帳號授權 CLI
wrangler whoami              # 確認登入哪個帳號

wrangler dev                 # 本機 8787 起 Worker(沙箱版資料庫)
wrangler dev --remote        # 本機程式碼,但連真的 D1/R2,能收真實 webhook
wrangler tail                # tail -f 等價物,看上線版的 log

# D1
wrangler d1 create family-bot-db
wrangler d1 execute family-bot-db --file schema.sql --remote   # 跑 SQL
wrangler d1 execute family-bot-db --command "SELECT * FROM messages LIMIT 10" --remote

# R2
wrangler r2 bucket create family-bot-attachments
wrangler r2 object list family-bot-attachments

# Secret
wrangler secret put LINE_CHANNEL_SECRET    # 互動式,貼值 + Enter
wrangler secret list

# 部署
wrangler deploy              # 一鍵打包 + 推到全球節點
wrangler deployments list    # 看歷史版本
wrangler rollback            # 回上一版

TypeScript 對你的最小子集

20 年前的 JS 加上這些就是 TS:

// 變數型別
const name: string = "mom";
const count: number = 5;
const ok: boolean = true;

// 函式型別
function greet(who: string): string { return `hi ${who}`; }

// 物件型別
interface Message {
  id: string;
  ts: number;
  type: "file" | "text";    // union — 只能是這兩個值
  filename?: string;        // 加了 ? 表示可省略
}

// async/await(你以前可能沒用過,比 callback 乾淨)
async function fetchSomething(): Promise<string> {
  const r = await fetch("https://example.com");
  return await r.text();
}

其他語法(迴圈、if、陣列、物件)跟你 20 年前寫的 JS 一樣。

跟 Apache 時代最大的心態差異

  1. 沒有 filesystem 可寫:所有狀態走 D1 / R2,寫完才存在。
  2. 每個 request 函式跑完就忘:別在全域變數放東西指望下次還在。
  3. 本機跟線上極像wrangler dev --remote 直接用真資料庫,沒有「我本機 PHP 7、線上 PHP 5」這種版本噩夢。
  4. 部署 = 一個指令 + 幾秒:以前 scp + restart apache 是一個流程,現在 wrangler deploy 完事。
  5. 想 debug 線上狀況wrangler tail 一直開著,搭配 console.log() 大法,跟 PHP error_log() 一樣土法煉鋼但有效。