學習目標:了解 curl 的基本操作與指令,並利用 curl 實作 CRUD 以及 挑戰 Lidemy HTTP Challenge
由於會進行 API 的操作,其中也會說明到一些 request 跟 response 中的小細節。
關於學習 curl 的心得,主要源自於以下學習資源:
- Linux Curl Command 指令與基本操作入門教學
- curl.md
- Everything curl
- curl 官網教學
- 驗證(Authentication)與授權(Authorization)的區別
- 開發者必備知識 — HTTP認證(HTTP Authentication)
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/
- 變化型:
curl [URL…] > text.txt
:將得到的內容打印在文件中 - 範例:
curl https://github.com/ > text.html
當我們把 text.html 打開之後,我們會得到一個跟在瀏覽器https://github.com/ 後很相似的頁面
[補充說明] 為什麼 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 output、CURL WRITE-OUT JSON
第二關:Read 得到單一用戶資料
- path:
/api/users/:id
- Http Method:
GET
- curl 指令:
curl “https://reqres.in/api/users/1"
這關跟第一關差不多,但假設我們輸入不存在的資料呢?
curl "https://reqres.in/api/users/24"
我們可以使用 -i,--include
,在 output 中顯示 response 的 header
舉例:curl "https://reqres.in/api/users/24" -i
第三關: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 送出表單,那網址會變成怎麼樣呢?
所以第一種就是 default 方式 Content-Type 會直接帶入 application/x-www-form-urlencoded
,但有時候我們需要傳遞 JSON 格式(也就是第二種)因此所以我們要在 header 特別註明使用 JSON 格式,否則存取的資料會產生錯誤。
Content-type
- 說明傳輸過去的內容類型
- 常見的類型
text/html
: HTML格式text/xml
: XML格式application/json
: JSON數據格式application/octet-stream
: 二進制流數據(如常見的文檔下載application/x-www-form-urlencoded
: form表單數據被編碼為key/value格式發送到服務器(表單默認的提交數據的格式)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:
User-Agent
(使用者代理):識別發出 client 端代理請求的軟體類型或版本號Content-Type
(HTTP 內容類型):指定攜帶的 HTTP Data 的格式Origin
:指示 request 的來源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 前進下一關,此遊戲網路知識含帶量蠻大的
因此在實戰前你應該要了解…
- Query string 是什麼:[JS] 使用 JavaScript 解析網址與處理網址中的參數(URL Parameters)
- 傳送 request 的方式,本篇文章是使用: curl
- 知道怎麼串接 API
第一關:你的名字(君の名は)
你叫做什麼名字呢?用 GET 方法跟我說你的 name 叫做什麼吧!除了 token 以外順便把 name 一起帶上來就可以了
- 需要思考的是…
如何使用 GET 帶上 name 資料傳遞過去?
我們知道傳送表單內容有 2 種 http method:GET、POST,GET 會以 query string 的方式傳送資料,白話來說就是會將傳遞的資訊直接寫在 url 上,所以直接修改 url 就可以囉
- 進關: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=mia
- 下一關 token:{HellOWOrld}
第二關: 忘東忘西是「初老」症狀
我只記得那本書的 id 是兩位數,介於 54~58 之間,你可以幫幫我嗎?找到是哪一本之後把書的 id 用 GET 傳給我就行了。
- 需要思考的是…
如何使用 GET 帶上 id 資料傳遞過去?
這跟第一關雷同,換湯不換藥,我們直接將 id 以 query string 的方式傳入。
- 進關:https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56
- 下一關 token:{5566NO1}
第三關:大腦喜歡這樣學
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"
- 進關:https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}&id=1989
- 下一關 token:{LEarnHOWtoLeArn}
第四關:村上春樹住在我的青春裡
API 相關資訊 — — — — —
1. 文件:圖書館資訊系統
2. API ENDPOINT:https://lidemy-http-challenge.herokuapp.com/api
我想找的那本書,書名有:「世界」兩字,而且是村上春樹寫的,可以幫我找到書的 id 並傳給我嗎?
- 需要思考的是…
1. 如何得到書籍清單 / 2. 如何對清單進行搜尋
清單的部分可以直接發出 GET 得到,搜尋的部分,我們可以想想每天在 goolge 時網址是不是發生了什麼變化?
- 進關:https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}&id=79
- 下一關 token:{HarukiMurakami}
第五關:寫真書不是書
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 知道我們是誰
- 如何將帳號密碼變成 base64 編碼:透過 online base64 將字串進行轉換。
- Basic Authentication 是什麼
- 如何 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
- 進關:https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}&email=lib@lidemy.com
- 下一關 token:{SECurityIsImPORTant}
第七關:偷書賊
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)"
- 進關:https://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}&version=1A4938Jl7
- 下一關 token:{duZDsG3tvoA}
第十關:我猜我猜我猜猜猜
出題者會出一個四位數不重複的數字,例如說 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!!!}
第十五關:成功!
以上有任何錯誤的地方歡迎指正,感謝。