[curl] 基本操作與指令
搭配 Lidemy HTTP Challenge 實作

MiaHsu
25 min readJul 19, 2020

--

學習目標:了解 curl 的基本操作與指令,並利用 curl 實作 CRUD 以及 挑戰 Lidemy HTTP Challenge

由於會進行 API 的操作,其中也會說明到一些 request 跟 response 中的小細節。

關於學習 curl 的心得,主要源自於以下學習資源:

curl

全名 CommandLine URL,從字面上的意思就可以知道是在 Command Line 的環境下,透過 HTTP 協定及利用 URL 規則進行資訊傳遞的工具,簡單來說就是可以透過它進行 request 及 response 的操作,優點在於:

  • 功能強大,任何網路相關的操作都可以透過 curl 進行。
  • 只需要透過短短幾行指令就可以發送出 request,因此很適合拿來做測試使用。
  • 支援檔案的上傳和下載。

如何使用 curl

操作的話就是使用 cmd 進行操作。

mac 的部分

都有內建,如果想要升級當前版本的話可以利用 homebrew (如果是一般操作的話,基本上是不用升級的)

windows 的部分

從 win10 v1804 起才有內建,在此之前的版本需要安裝才能使用 curl 的指令:下載網址

查看當前版本

$ curl — version

以下會先說明基本的操作

curl 基本指令

在開始之前我們先來了解 Curl 的基本格式

  • 格式:curl [options] [URL…]
  • 需要傳遞字串時需在字串的兩邊加上雙引號
  • - 代表短指令(縮寫);-- 長指令,使用哪一種都可以。
    舉例: -d 等同於 -— data

curl [URL…]

  • 得到 Response body,等同於在瀏覽器上輸入網址,只是回傳的內容是印在 cmd 上。
  • 舉例:curl https://github.com/
在 cmd 上輸入 curl https://github.com/ 得到的結果
  • 變化型:
    curl [URL…] > text.txt:將得到的內容打印在文件中
  • 範例:curl https://github.com/ > text.html
傳輸進度條

當我們把 text.html 打開之後,我們會得到一個跟在瀏覽器https://github.com/ 後很相似的頁面

text.html
[補充說明] 為什麼 curl 印在終端機上的是一大堆文字但用瀏覽器打開卻變成網頁?藉由 curl 我們可以了解到網址後得到的就只是一大堆的文字,但是經過瀏覽器的解析就會變成我們看到的網頁畫面,瀏覽器跟 cmd 都是應用程式,只是兩者對於那一大傳的文字有不同的解析,所以我們可以知道…1. 從瀏覽器輸入網址後得到的其實是一大串文字,但瀏覽器對於這些文字有著不同的解析,變成了我們看到的網頁。2. 從 cmd 用 curl 指令輸入網址後得到的其實是一大串文字,因為這些文字對於 cmd 來說就只是文字。3. 「從 cmd 用 curl 指令」等同於「從瀏覽器輸入網址」他們都是透過網路進行資訊的交換。

下載檔案

  • 下載檔案到當前路徑
  • 指令:
    curl -o [fileName] [URL]:為下載的檔案重新命名
    curl -O [URL]:直接使用遠端名稱作為檔名
  • 範例:
curl -O https://static.coderbridge.com/img/techbridge/images/kdchang/cs101/terminal.jpg
將一張圖片下載下來

Verbose / Debug

  • 如果 curl 失敗,可以透過指令了解整個 curl 過程
  • 指令:
    curl -v [URL]:顯示接收及發送的訊息
    curl — trace-ascii [fileName] [URL]
    :顯示更多詳細訊息
  • 舉例:curl — trace-ascii debugdump.txt http://www.example.com/

實戰1. 利用 curl 指令進行 CRUD (共五關)

這個實戰的目標是完成簡單的 CRUD and List 功能

等等等等,介紹的指令也太少了吧…

我自己初探 curl 找資料時看到介紹指令的文章,當下還是不太清楚用法,其中很大的原因是因為我跟 cmd 不是很熟,所以沒辦法馬上轉換成我想要達成目的的指令,因此希望可以藉由簡單的 API 執行 CRUD 藉此熟悉,當中再詳細說明各個指令的用途。

這邊使用的 API 為 Regres,這邊簡單說明一下 API 的提供的方法:

  • 提供測試資料,回傳資料的格式為 JSON 格式字串
  • 提供的 HTTP Method 有: GET/ POST/ PUT /PATCH/ DELETE
  • API ENDPOINT:https://reqres.in/

第一關:List 得到用戶清單資料

  • path:/api/users
  • 可使用參數:page=<number>
  • Http Method:GET
  • curl 指令: curl "https://reqres.in/api/users?page=2"
回傳第二頁的資料

只要使用基本的用法就可以得到資料,這關我們可以了解到…

其實就跟在瀏覽器的網址列上輸入 url 得到的是一樣的,也就是使用 GET 發出 Request

Q:curl 是否有指令將資料直接轉為 JSON 格式?A:目前版本不行,未來可能會有,參考資料:writeout: support to generate JSON outputCURL WRITE-OUT JSON

第二關:Read 得到單一用戶資料

  • path:/api/users/:id
  • Http Method:GET
  • curl 指令: curl “https://reqres.in/api/users/1"
回傳 id 等於 1 的資料

這關跟第一關差不多,但假設我們輸入不存在的資料呢?

curl "https://reqres.in/api/users/24"
會回傳空值,但我們不確定到底是什麼情況

我們可以使用 -i,--include ,在 output 中顯示 response 的 header

舉例:curl "https://reqres.in/api/users/24" -i

就可以知道 http method

第三關:Creat 新增一筆資料

  • path:/api/users
  • Http Method:POST
  • curl 指令

第一種 Form post:

curl "https://reqres.in/api/users/" -d "name=mia&job=leader"

第二種 JSON post:

curl "https://reqres.in/api/users/" -d '{"name"]" : "mia", "job": "leader"}' -H "Content-Type: application/json"
  • 指令說明:
    -d, --data:攜帶 HTTP Data
    -H, --header:設定 request 裡要攜帶的 header

兩種指令的差異在於:傳遞過去的 data 格式不同,第一種是一般表單的形式送出、第二種是直接以 JSON 的形式送出。

假設我們是用 GET 送出表單,那網址會變成怎麼樣呢?

會以 query string 的方式傳送資料

所以第一種就是 default 方式 Content-Type 會直接帶入 application/x-www-form-urlencoded,但有時候我們需要傳遞 JSON 格式(也就是第二種)因此所以我們要在 header 特別註明使用 JSON 格式,否則存取的資料會產生錯誤。

Content-type

  • 說明傳輸過去的內容類型
  • 常見的類型
  1. text/html : HTML格式
  2. text/xml : XML格式
  3. application/json : JSON數據格式
  4. application/octet-stream : 二進制流數據(如常見的文檔下載
  5. application/x-www-form-urlencoded : form表單數據被編碼為key/value格式發送到服務器(表單默認的提交數據的格式)
  6. multipart/form-data : 表單中有涉及到文檔上傳時需使用該格式

第四關:Update 更新資料

  • path:/api/users/:id
  • Http Method:PUT、PATCH
  • curl 指令:

第一種 Form post:

curl -X PATCH "https://reqres.in/api/users/1" -d "name=mia&job=leader"

第二種 JSON post:

curl -X PATCH "https://reqres.in/api/users/1" -d '{"name" : "mia", "job": "leader"}' -H "Content-Type: application/json"
  • 指令說明
    -X, --request:在後方加上 http metode 可以更改 curl 選擇的方法關鍵字

第五關:Delete 刪除資料

  • path:/api/users/:id
  • Http Method:DELETE
  • curl 指令:curl -X DELETE “https://reqres.in/api/users/1" -i
  • 指令說明:
    -i, --include:output response 的 header

這樣就完成利用 curl 做出 CRUD 囉

小結指令整理

-X, --request

  • 在後方加上 http metode 可以更改 curl 選擇的方法關鍵字。
  • Http Method:GET、POST、PUT、DELETE、PATCH
  • 如果沒有特別指定 curl 會依據求採取的動作自行選擇使用哪些方法,比如說:如果傳 -d 將會執行 POST, -i 會執行 HEAD 等
  • 範例:

curl https://reqres.in/api/users/1 以 GET 發出

curl -X DELETE https://reqres.in/api/users/1 以 DELETE 發出

[補充說明] 在查資料的時候這邊卡了一陣子,因為「但不會修改 curl 的行為。」這句話是出自官方文件,代表其實根本沒有需要用到 -X 的必要?某篇文章也有討論到這個問題 UNNECESSARY USE OF CURL -X,但根據範例,假設我想刪除某筆資料,就必定要帶上  -X DELETE ,因此我想可能也會因為 API 的設計有不同的使用,所以對於這個指令的正確使用還沒有到非常理解。

-d, --data

  • 攜帶 HTTP Data 發出 request
  • 默認 Content-Type 方式為 application/x-www-form-urlencoded
  • 範例:curl "https://reqres.in/api/users/" -d "name=mia&job=leader"

-H, --header

  • 設定 request 裡要攜帶的 header
  • 常用的 HTTP Header:
  1. User-Agent(使用者代理):識別發出 client 端代理請求的軟體類型或版本號
  2. Content-Type(HTTP 內容類型):指定攜帶的 HTTP Data 的格式
  3. Origin:指示 request 的來源
  4. Authorization:授權,根據使用者的角色來授予應有的權限

因為可以設定的參數相當多,這邊提供 MDN 的說明作為參考:HTTP headers

  • 範例:將攜帶的 HTTP Data 格式改為 JSON
curl "https://reqres.in/api/users/" -d '{"name" : "mia", "job": "leader"}' -H "Content-Type: application/json"

-i, --include

  • output response 的 header,是很常用到的指令
  • 可以用來:
    1. 查看 HTTP status code
  • 範例:curl -X DELETE "https://reqres.in/api/users/1" -i

實戰2. 利用 curl 指令進行 Lidemy HTTP Challenge

這個實戰的目標是用剛剛學到得指令來闖關 HTTP Challenge

遊戲連結:https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}

這是一個小遊戲,透過發出 request 得到前進下一關 token 並用 Query string 前進下一關,此遊戲網路知識含帶量蠻大的

因此在實戰前你應該要了解…

  1. Query string 是什麼:[JS] 使用 JavaScript 解析網址與處理網址中的參數(URL Parameters)
  2. 傳送 request 的方式,本篇文章是使用: curl
  3. 知道怎麼串接 API
那我們就開始吧~

第一關:你的名字(君の名は)

你叫做什麼名字呢?用 GET 方法跟我說你的 name 叫做什麼吧!除了 token 以外順便把 name 一起帶上來就可以了
  • 需要思考的是…

如何使用 GET 帶上 name 資料傳遞過去?

我們知道傳送表單內容有 2 種 http method:GET、POST,GET 會以 query string 的方式傳送資料,白話來說就是會將傳遞的資訊直接寫在 url 上,所以直接修改 url 就可以囉

第二關: 忘東忘西是「初老」症狀

我只記得那本書的 id 是兩位數,介於 54~58 之間,你可以幫幫我嗎?找到是哪一本之後把書的 id 用 GET 傳給我就行了。
  • 需要思考的是…

如何使用 GET 帶上 id 資料傳遞過去?

這跟第一關雷同,換湯不換藥,我們直接將 id 以 query string 的方式傳入。

第三關:大腦喜歡這樣學

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api

書名是《大腦喜歡這樣學》,ISBN 為 9789863594475。新增完之後幫我把書籍的 id 用 GET 告訴我。
  • 需要思考的是…

如何「新增」書籍?

想想實戰1 的 CRUD,我們可以用 POST 並攜帶 HTTP Data 發出 request。

  • curl 指令:
curl -X POST "https://lidemy-http-challenge.herokuapp.com/api/books" --data "name=大腦喜歡這樣學&ISBN=9789863594475"
成功新增書籍

第四關:村上春樹住在我的青春裡

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api

我想找的那本書,書名有:「世界」兩字,而且是村上春樹寫的,可以幫我找到書的 id 並傳給我嗎?
  • 需要思考的是…

1. 如何得到書籍清單 / 2. 如何對清單進行搜尋

清單的部分可以直接發出 GET 得到,搜尋的部分,我們可以想想每天在 goolge 時網址是不是發生了什麼變化?

我們發現 Query string 使用 q= 就可以搜尋關鍵字

第五關:寫真書不是書

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api

那本書的 id 是 23,你可以幫我刪掉嗎?
  • 需要思考的是…

如何「刪除」書籍

想想實戰1 的 CRUD,我們可以利用將 Http method 改為 DELETE ,進行刪除的動作。

  • curl 指令:
curl -X DELETE "https://lidemy-http-challenge.herokuapp.com/api/books/23"
  • 下一關 token:{CHICKENCUTLET}

第六關:你媽媽沒跟你說過不要亂動別人的東西嗎

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v2
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v2

照理來說要進入系統應該要先登入才對,怎麼沒有登入就可以新增刪除…這邊是帳號密碼,你先登入試試看吧,可以呼叫一個 /me 的 endpoint,裡面會給你一個 email。把 email 放在 query string 上面帶過來,我看看是不是對的。帳號:admin密碼:admin123
  • 需要思考的是…

在傳遞資訊中安全性的問題

在一般情況下不可能隨意讓人動 Server 的資料,因此傳遞資訊的過程當中很重要的一點是認證發出 request 的人是誰?是否有這個權限?我們必須解決以下問題,才能順利讓 Server 知道我們是誰

  1. 如何將帳號密碼變成 base64 編碼:透過 online base64 將字串進行轉換。
  2. Basic Authentication 是什麼
  3. 如何 request header 加入 Authorization:-H, --header 設定 request 裡要攜帶的 header

HTTP Authentication

是 Client 端在發送 Request 時在 Header 強制進行身份驗證,HTTP Authentication 有多種方式進行驗證,而是 Basic Authentication 是最簡單方便快捷的方法,其內容為 base64(username:password)。

更詳細的說明可參考:開發者必備知識 — HTTP認證(HTTP Authentication)

  • curl 指令:
curl "https://lidemy-http-challenge.herokuapp.com/api/v2/me"  -H "Authorization: Basic YWRtaW46YWRtaW4xMjM="
  • 偷吃步作法:

-u, --user

  • HTTP Authentication 身份驗證
  • curl 提供當用 Basic Authentication 時的指令,可以直接輸入 username:password 不用額外將字串轉換成 base64
  • 範例:
curl "https://lidemy-http-challenge.herokuapp.com/api/v2/me" -u admin:admin123

第七關:偷書賊

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v2
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v2

我們要把這本書從系統裡面刪掉,就拜託你了。書的 id 是 89。

帶上帳號密碼發出 DELETE 就可以了

  • curl 指令
curl -X DELETE "https://lidemy-http-challenge.herokuapp.com/api/v2/books/89" -H "Authorization: Basic YWRtaW46YWRtaW4xMjM="
  • 下一關 token:{HsifnAerok}

第八關:日日好日

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v2
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v2

那本書的名字裡面有個「我」,作者的名字是四個字,key 錯的 ISBN 最後一碼為 7,只要把最後一碼改成 3 就行了。
  • 需要思考的是…

如何「更新」書籍資料

  • curl 指令
curl "https://lidemy-http-challenge.herokuapp.com/api/v2/books/72"  -H "Authorization: Basic YWRtaW46YWRtaW4xMjM="  -X PATCH --data "ISBN=9981835423"
  • 下一關 token:{NeuN}

第九關:客製化

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v2
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v2

API 文件裡面有個獲取系統資訊的 endpoint 你記得嗎?工程師跟我說這個網址不太一樣,用一般的方法是沒辦法成功拿到回傳值的。想要存取的話要符合兩個條件:1. 帶上一個 X-Library-Number 的 header,我們圖書館的編號是 202. 伺服器會用 user agent 檢查是否是從 IE6 送出的 Request,不是的話會擋掉順利拿到系統資訊之後應該會有個叫做 version 的欄位,把裡面的值放在 query string 給我吧。
  • 需要思考的是…

1. 客製化 request 的 header / 2. 了解 user agent

User-Agent(使用者代理)

能夠識別發出 client 端代理請求的軟體類型或版本號,IE6 版本號參考。

  • curl 指令
curl "https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info"  -H "Authorization: Basic YWRtaW46YWRtaW4xMjM=" -H "X-Library-Number: 20" -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"

第十關:我猜我猜我猜猜猜

出題者會出一個四位數不重複的數字,例如說 9487。你如果猜 9876,我會跟你說 1A2B,1A 代表 9 位置對數字也對,2B 代表 8 跟 7 你猜對了但位置錯了。開始吧,把你要猜的數字放在 query string 用 num 當作 key 傳給我。

這關單純猜數字 XD

  • 進關:https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}&num=9613
  • 下一關 token:{IhateCORS}

第十一關:來自菲律賓的書

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v3
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v3

現在就讓我們先跟他們打個招呼吧,只是我記得他們的 API 好像會限制一些東西就是了…

如果我們直接發出 request https://lidemy-http-challenge.herokuapp.com/api/v3/hello 將會得到

您的 origin 不被允許存取此資源,請確認您是從 lidemy.com 送出 request。

需要思考的是…

跨來源資源共用問題

有關於同源政策可參考:[第九週]透過瀏覽器交換資料 — 同源政策、CORS、第三種方式 JSONP 或清楚易懂教學(需付費):Lidemy — Same origin policy 與跨網域問題

我們可以在 request header 加上 origin: url 就可以騙過伺服器

  • curl 指令
curl "https://lidemy-http-challenge.herokuapp.com/api/v3/hello" -H "origin: lidemy.com"
  • 下一關 token:{r3d1r3c7}

第十二關:轉啊轉

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v3
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v3

現在請你幫我把運送要用的 token 給拿回來吧,要有這個 token 我們才能繼續往下一步走

直接輸入 https://lidemy-http-challenge.herokuapp.com/api/v3/deliver_token 得到我已經把運送要用的 token 給你囉,請你仔細找找

需要思考的是…

轉址

仔細看一下 path 變成了 /deliver_token_result
這是因為 Server 端設定當訪問 /deliver_token 轉成 /deliver_token_result

因此我們可以打開 DevTool Network 重新輸入一次網址

  • 下一關 token:{qspyz}

第十三關:MABUHAY

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v3
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v3

最近碰到了一些小問題,不知道為什麼有時候會傳送失敗我跟他們反映過後,他們叫我們自己去拿 log 來看,你可以幫我去看看嗎?從系統日誌裡面應該可以找到一些端倪

直接輸入 https://lidemy-http-challenge.herokuapp.com/api/v3/logs 得到,此 request 不是來自菲律賓,禁止存取系統資訊。

需要思考的是…

如何假裝我們是從菲律賓來的

代理伺服器 Proxy

以類似代理人的身份去跟 Server 端取得需要的資料,參考資料:第十七章、區網控制者: Proxy 伺服器 — by 鳥哥

  • 菲律賓代理伺服器
  • curl 上有相關的指令,但…看不懂怎麼使用,因此我是用 Postman 操作這關需要點耐心會要嘗試個很多次才有機會成功,畢竟不是每個 IP 都可以用。
  • 下一關 token:{SEOisHard}

第十四關:人人都想做好 SEO

API 相關資訊 — — — — —
1. 文件:圖書館資訊系統v3
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api/v3

為什麼用 Google 一搜尋關鍵字就可以排在第一頁,真是太不合理了難道說他們偷偷動了一些手腳?讓 Google 搜尋引擎看到的內容跟我們看到的不一樣?

這邊我們需要去理解的是…

可以透過 User-Agent 定義每個瀏覽器不同的抓取規則優化 SEO

參考資料:关于Robots.txt和SEO: 你所需要知道的一切

所以我們只要把 User-Agent 改為 Google 檢索器,就可以讓 Server 端辨認出瀏覽器

  • curl 指令
curl "https://lidemy-http-challenge.herokuapp.com/api/v3/index" -H "User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
  • 下一關 token:{ILOVELIdemy!!!}

第十五關:成功!

以上有任何錯誤的地方歡迎指正,感謝。

--

--