看得懂貼上的 curl,查 API 就會快很多

從文件或瀏覽器開發者工具複製來的 curl 指令,通常長這樣:

curl -X POST 'https://api.example.com/v1/items?limit=10' \
  -H 'Authorization: Bearer TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Alice","tags":["a","b"]}'

看得懂之後其實很單純,但有幾處選項組合會改變行為,不知道就會遇到「同一段指令在這裡卻不能用」。

主要選項速查表

選項意義
-X, --request指定 HTTP 方法(GET / POST / PUT / DELETE
-H, --header加入請求標頭,可重複使用
-d, --data送出請求主體。加了就會變成 POST
--data-raw-d 相同,但不把開頭的 @ 當成檔名
-F, --formmultipart/form-data 送出(上傳檔案)
-u, --user基本驗證(user:password
-L, --location追蹤重新導向(3xx)
-o, --output將回應寫入檔案
-O, --remote-name以 URL 結尾的檔名儲存
-s, --silent不顯示進度
-S, --show-error搭配 -s,但仍顯示錯誤
-i, --include輸出中包含回應標頭
-I, --head送出 HEAD,只看標頭
-v, --verbose顯示完整往返內容,包含請求標頭
-k, --insecure驗證伺服器憑證
--compressed要求壓縮傳輸
-b, --cookie送出 Cookie
-c, --cookie-jar將收到的 Cookie 存成檔案
-w, --write-out結束後輸出 %{http_code} 等資訊

-X POST 多半可以省略

只要加上 -d,curl 就會自動變成 POST。下面兩行是一樣的:

curl -X POST https://api.example.com/items -d '{"a":1}'
curl https://api.example.com/items -d '{"a":1}'

麻煩的是反過來的情況。-X GET 搭配 -d 會產生帶有主體的 GET 請求,某些 Proxy 與伺服器會忽略或拒絕,是「本機可以、正式環境失敗」的經典原因。

另外 -d 寫多次會用 & 串起來。對表單送出很方便,對 JSON 則是災難:

# 與預期不同:送出的是 {"a":1}&{"b":2}
curl -d '{"a":1}' -d '{"b":2}' https://api.example.com/items

-d 開頭的 @ 會變成讀取檔案

當傳給 -d 的值以 @ 開頭時,curl 會讀取該檔案並送出其內容

curl -d @payload.json https://api.example.com/items   # 送出檔案內容

很方便,但把帳號或信箱原樣傳入就會出事:

# 本意:送出字串 "@alice"
# 實際:curl 去找 ./alice 這個檔案,找不到就報錯
curl -d '@alice' https://api.example.com/items

要原樣送出含 @ 的值,請用 --data-raw,它不會對 @ 做特殊處理。

Content-Type 不會自動變成 JSON

使用 -d 時,若未特別指定,curl 會送出 Content-Type: application/x-www-form-urlencoded。以為在送 JSON 卻忘了標頭,伺服器就會解析失敗:

curl -H 'Content-Type: application/json' \
     -d '{"name":"Alice"}' https://api.example.com/items

curl 7.82 之後有 --json,會同時設定 Content-Type: application/jsonAccept: application/json。但舊環境沒有這個選項,要分享的指令還是明確寫出標頭比較保險。

引號用法是最大的出錯來源

寫法行為
'...'(單引號)原樣傳遞內部的 $"送 JSON 用這個
"..."(雙引號)Shell 會展開 $變數

JSON 本身含有雙引號,所以外層要用單引號

# 正確
curl -d '{"name":"Alice"}' https://api.example.com/items

# Shell 會把內層引號剝掉,主體就壞了
curl -d "{"name":"Alice"}" https://api.example.com/items

若需要從環境變數帶入權杖,就刻意混用兩者:

curl -H "Authorization: Bearer $TOKEN" \
     -d '{"name":"Alice"}' https://api.example.com/items

Windows 命令提示字元不會解析單引號,而 PowerShell 中的 curl 有可能是 Invoke-WebRequest 的別名。請明確呼叫 curl.exe,或改在 WSL、Git Bash 執行。

URL 含 & 時要用引號括起來

直接貼上含多個參數的 URL,Shell 會把 & 解讀成「放到背景執行」,指令就被截斷了:

# 壞掉:只送出 limit=10
curl https://api.example.com/items?limit=10&offset=20

# 正確
curl 'https://api.example.com/items?limit=10&offset=20'

含空白或非 ASCII 字元的值需要百分比編碼。可以用 URL 編碼/解碼 確認,或交給 curl 以 -G 搭配 --data-urlencode 安全地組出查詢字串:

curl -G https://api.example.com/search --data-urlencode 'q=台北 101'

兩個不該隨手加上的選項

-k / --insecure 會關閉憑證驗證。在本機測試自簽憑證時有其用途,但為了消除錯誤而加上、然後就這樣被分享或帶進正式環境,是最典型的事故。 憑證問題應該在憑證那端解決。

-L / --location 會追蹤重新導向。很方便,但 POST 被導向時,方法與主體的處理可能改變;需要固定行為時,可用 --post301--post302--post303 明確指定。

把讀懂的 curl 直接變成程式碼

把讀懂的 curl 搬進應用程式時,手動抄寫標頭與主體很容易出錯。貼進 cURL 轉換器,就能轉成 JavaScript、Python、Go 等語言的請求程式碼,引號對應與標頭拆解都由工具處理。

要格式化或檢查要送出的 JSON,可用 JSON 格式化工具;想看查詢字串的內容,可用 URL 參數轉 JSON。這些都在瀏覽器內完成,即使貼上含權杖的指令也不會傳送到外部。

總結

  • 加了 -d 就自動是 POST;-X GET 搭配 -d 會變成不好處理的「帶主體的 GET」
  • -d 的值以 @ 開頭會讀取檔案,要當字串送就用 --data-raw
  • 只用 -d 是表單格式;送 JSON 要明確給標頭,或使用 --json(curl 7.82+)
  • 送 JSON 時外層用單引號,只有需要展開變數的地方才用雙引號
  • URL 含 & 要用引號括住;值的編碼交給 -G --data-urlencode 最安全
  • -k 不是拿來消除錯誤的工具,-L 可能改變 POST 的行為

常見問題

一定要寫 -X POST 嗎?

通常不用,加上 -d-F 時就會自動成為 POST。不過寫出來能表達意圖,在要分享的指令中仍有價值。該避免的是 -X GET 搭配 -d,那會變成帶主體的 GET,部分伺服器與 Proxy 會忽略或拒絕。

-d--data-raw 差在哪裡?

只差在開頭 @ 的處理。-d 會把 @ 後面的字串當成檔名並送出檔案內容,--data-raw 則原樣送出字串。要送出本來就含 @ 的資料(例如電子郵件),請用 --data-raw

我送了 JSON,伺服器卻無法解析

使用 -d 時預設的 Content-Typeapplication/x-www-form-urlencoded,所以需要加上 -H 'Content-Type: application/json'。curl 7.82 之後可用 --json 一併設定標頭。

指令在 Windows 上不能執行

命令提示字元不解析單引號,PowerShell 的 curl 也可能是 Invoke-WebRequest 的別名。請明確呼叫 curl.exe,或改用 WSL、Git Bash 等會解析單引號的 Shell。

貼上含權杖的指令安全嗎?

cURL 轉換器 完全在瀏覽器內處理,貼上的內容不會被傳送。但轉換後的程式碼仍含有權杖,建議在提交程式碼前先改成環境變數。