Lidemy HTTP challenge

Http 圖書館一日小弟心得

遊戲開始

Note

Start: 遊戲解說

安安,歡迎來到 Lidemy HTTP challenge。

這裡一共有 10 道關卡,每一關的網址皆為 /lvX,X 即為關卡的數字。

但只知道網址是沒有用的,需要搭配正確的 token 才能順利進入關卡,傳入 token 的方式為 query string,例如 /lv1?token=xxx。

另外,為了讓你方便辨別這是 token,token 的內容一定是用一個大括弧刮起來的字串。

每一關都會有提示,只要按照提示照著做,就能拿到前往下一關的 token。

準備好了嗎?

第一關的 token 為:{GOGOGO}

Lv1

  • 啊...好久沒有看到年輕人到我這個圖書館了,我叫做 lib,是這個圖書館的管理員。
  • 很開心看到有年輕人願意來幫忙,最近圖書館剛換了資訊系統,我都搞不清楚怎麼用了...這是他們提供給我的文件,我一個字都看不懂,但對你可能會有幫助:https://gist.github.com/aszx87410/3873b3d9cbb28cb6fcbb85bf493b63ba
  • 你叫做什麼名字呢?用 GET 方法跟我說你的 name 叫做什麼吧!

GET - Query string

  • 一開始不太懂這個是在問什麼,有個概念,但是方向不對,打轉了摸索了好陣子啊!知道要打上「&name=enter3017sky」但是不知道要打去哪裡。
  • 後來回過神了,回頭再看看管理員,然後看看「圖書館資訊系統 API 文件」靜心想了一下。
  • 後來才恍然大悟,既然是管理員跟我說的,眼前這個網頁的網址列就是這個管理員呀!
  • https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=enter3017sky
  • 這樣就可以得到下一關 token 了!
  • 啊...原來你叫 enter3017sky 啊!下一關的 token 是 {HellOWOrld}
  • https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}
  • 拿到 lv2 的 token 之後,像 lv1 一樣,用 GET 方法,以 query string 的方式,在網址列輸入即可。

Lv2

  • 我前陣子在整理書籍的時候看到了一本我很喜歡的書,可是現在卻怎麼想都想不起來是哪一本...
  • 我只記得那本書的 id 是兩位數,介於 54~58 之間,你可以幫幫我嗎?
  • 找到是哪一本之後把書的 id 用 GET 傳給我就行了。
  • 跟第一關一樣,query string 的方式輸入 id 為 54~58 之間的書籍,看看答案是否正確,就可以取得 lv3 的 token 了
  • 猜一下吧!
  • 如果猜錯了,管理員會說「好像不是這本書耶...」
  • 猜中了「啊!就是這本書,太謝謝你了。下一關的 token 為:{5566NO1}」
  • 即可得到第三關的 token 啦!

Lv3

  • 真是太感謝你幫我找到這本書了!
  • 剛剛在你找書的時候有一批新的書籍送來了,是這次圖書館根據讀者的推薦買的新書,其中有一本我特別喜歡,想要優先上架。
  • 書名是《大腦喜歡這樣學》,ISBN 為 9789863594475。
  • 就拜託你了。
  • 新增完之後幫我把書籍的 id 用 GET 告訴我。
  • 第三關本來想說用 fetch 的 POST傳資料看看,但是不知道為何不能從 Network Tab 直接看到 Response 的答案,所以弄了一個表單。
lv3 POST 新增書籍
  • 第二個方式:Command Line 下 curl 指令
  • ~$ curl -X POST -d "name=大腦喜歡這樣學&ISBN=9789863594475" https://lidemy-http-challenge.herokuapp.com/books
    {"message":"新增成功","id":"1989"}
  • 馬上就取得下一關的線索了!

  • 以下還要驗證一下。
  • 第三個方式:但是 Response 查看不到答案
  • const url = 'https://lidemy-http-challenge.herokuapp.com/books'
    fetch(url, {
        body: 'name=大腦喜歡這樣學&ISBN=9789863594475',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        method: 'POST',
    })
        .then(data => data.json())
        .then(result => console.log(result))

Lv4

  • 我翻了一下你之前幫我找的那本書,發現我記錯了...這不是我朝思暮想的那一本。
  • 我之前跟你講的線索好像都是錯的,我記到別本書去了,真是抱歉啊。
  • 我記得我想找的那本書,書名有:「世界」兩字,而且是村上春樹寫的,可以幫我找到書的 id 並傳給我嗎?
  • 從先前的「圖書館資訊系統 API 文件」,有點 api 概念的,就知道 https://lidemy-http-challenge.herokuapp.com/books
  • 就可以取得所有書籍的資料,然後再依照提示搜尋線索吧
  • 後來看到 前輩的筆記,她用了正確的方式(圖書館資訊系統 API 文件提供的 GET 方法查詢書籍)找到答案,而我是透過所有書籍去 command+F 去搜尋,筆記下來思路的不同。

Lv5

  • 昨天有個人匆匆忙忙跑過來說他不小心捐錯書了,想要來問可不可以把書拿回去。
  • 跟他溝通過後,我就把他捐過來的書還他了,所以現在要把這本書從系統裡面刪掉才行。
  • 那本書的 id 是 23,你可以幫我刪掉嗎?
  • DELETE 方法
  • 這邊也花了一些時間,想了一些方法,一直嘗試,突然靈光一閃,想到了 curl 這個指令!
  • 這個部分參考了很多文章,這篇 淺顯易懂,開箱即用
  • curl -X DELETE "https://lidemy-http-challenge.herokuapp.com/books/23

  • 以下還要驗證一下,跟 Lv3 一樣,不知道怎麼查看 Response
  • fetch('https://lidemy-http-challenge.herokuapp.com/books/23', {
        method: 'DELETE',
    }).then(data => console.log(data))

Lv6

  • 我終於知道上次哪裡怪怪的了!
  • 照理來說要進入系統應該要先登入才對,怎麼沒有登入就可以新增刪除...
  • 這太奇怪了,我已經回報給那邊的工程師了,他們給了我一份新的文件:https://gist.github.com/aszx87410/1e5e5105c1c35197f55c485a88b0328a
  • 這邊是帳號密碼,你先登入試試看吧,可以呼叫一個 /me 的 endpoint,裡面會給你一個 email。
  • 把 email 放在 query string 上面帶過來,我看看是不是對的。
  • 帳號:admin
  • 密碼:admin123
  • 很順利地來到這六關,但在這關卡了一下下,讓我意識到除了找資料、篩選資料,抓重點也是很重要的,忽略 Authorization 格式,就這個小細節,導致萬事不確定的情況下一直在嘗試,沒有邏輯、沒有根據的嘗試太恐怖了,筆記筆記。
  • 從新的文件得知,這份文件的所有 API 端點(endpoint)都需要 「HTTP Basic authentication」才能存取,然後驗證的方法是文件提供給你的 username/email 經過 base64 編碼後的結果。
  • 首先從最簡單的部分開始吧,查了一下 base64,然後想到利用 Chrome DevTools 是最方便的,所以利用 DevTools 內建的 btoa 函式,btoa('str'),將得到的帳號密碼轉換成 base64 的編碼(encode),atob('base64') 則是解碼(decode)
  • > btoa('admin:admin123')
    < "YWRtaW46YWRtaW4xMjM="
  • 雙引號裡面就是我們要的 base64 的結果了。
  • 最簡單的問題處理掉了,這時我就在想,我該用什麼東西發送我的請求而且還要附加 header 呢?
  • 表單?好像怪怪的?
  • 想著想著,想起最近有練習一下 fetch 抓 twitch API,這一切似乎都連貫起來了。
  • https://dev.twitch.tv/docs/api/ 裡面的 「Step 2: Sample Code」 就示範了,如果透過簡單的方式(command Line 的 curl 指令),向 API 要求然後獲取你要的結果「Step 3: Results」,而之前關卡就用上 curl ,是經過這關後嘗試並補上的XD。
  • MDN - Http 身份認證 裡面有提到,認證的格式「 Authorization: [type] [credentials] 」是這樣
  • 所以我們附上的 header 會是 “Authorization: Basic YWRtaW46YWRtaW4xMjM=”,但是在圖書館 API 文件就沒有講得很清楚,自己找的資料也沒看清楚QQ
  • 總之利用 curl GET 方法,就可以得到管理員要求的 email 了
  • ~$ curl -X GET -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM='  https://lidemy-http-challenge.herokuapp.com/v2/me
    {"username":"admin","email":"lib@lidemy.com"}
  • fetch 的方式再研究看看

Lv 7 - DELETE 刪除一本 id 為 89 的書籍

  • 那邊的工程師說系統整個修復完成了,剛好昨天我們發現有一本書被偷走了...
  • 這本書我們已經買第五次了,每次都被偷走,看來這本書很熱門啊。
  • 我們要把這本書從系統裡面刪掉,就拜託你了。
  • 對了!記得要用新的系統喔,舊的已經完全廢棄不用了。
  • 書的 id 是 89。
  • 第七關的需求跟之前的一樣,利用 curl 以及 http 認證的參數去刪除 id 89 的書
  • ~$ curl -X DELETE -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' https://lidemy-http-challenge.herokuapp.com/v2/books/89
    {"message":"希望下一次進這本書的時候不會再被偷走了。下一關的 token 為 {HsifnAerok}"}
    

Lv8 - PATCH 更改書籍的 ISBN

  • 我昨天在整理書籍的時候發現有一本書的 ISBN 編號跟系統內的對不上,仔細看了一下發現我當時輸入系統時 key 錯了。
  • 哎呀,人老了就是這樣,老是會看錯。
  • 那本書的名字裡面有個「我」,作者的名字是四個字,key 錯的 ISBN 最後一碼為 7,只要把最後一碼改成 3 就行了。
  • 對了!記得要用新的系統喔,舊的已經完全廢棄不用了。
  • 經過了一些嘗試,爬了很多文,以上終於成功了,最後是看了這篇改了一下 https://gist.github.com/subfuzion/08c5d85437d5d4f00e58,也熟悉了一下, curl 的操作,但是用 curl 轉換 fetch 無法 CORS ,應該是瀏覽器擋住了。
  • 傳送過去的 data 不確定要不要 urlencoded 也是蠻困擾的,這方面的資訊應該好好惡補一下。
  • 進去正題了!首先得搜尋出符合條件的書籍,我一開始一樣是搜尋全部,用fetch,取得全部書籍。
/** lv8: 或者是用 fetch,原本一直失敗(Invalid Authorization token)是因為
*  'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=', 這串少打 Basic
*  沒有打的情況下用 data.json() 會跳 “Unexpected token I in JSON at position 0”
*  「curl 指令轉換成 fetch https://kigiri.github.io/fetch/」
*/

const url = 'https://lidemy-http-challenge.herokuapp.com/v2/books';
fetch(url, {
    headers: {
        'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    method: 'GET',
}).then(data => {
    // 這裡會 log Response 出來
    console.log(data)
    return data
}).then(result => {
    // Promise {: Array(100)}
    console.log(result.json())
}).catch(err => console.log('error message:', err.message))
  • 參考過前輩更正確的做法後,fetch 中的 url 改成
  • const url = 'https://lidemy-http-challenge.herokuapp.com/v2/books?q=我'
  • 更方便篩選資料
  • 但是用 curl 指令時,中文字必須 encodeURIComponent 轉換,不然返回空陣列
// 剛剛用 fetch 成功,現在換 curl 看看
curl -X GET -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' https://lidemy-http-challenge.herokuapp.com/v2/books?q=我

管理員的關鍵字是「我」,經測試這樣返回一個空陣列,所以先用 Chrome DevTools 的內建函式轉換搜尋的關鍵字,試試看。

encodeURIComponent('我') => "%E6%88%91"

curl -X GET -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' https://lidemy-http-challenge.herokuapp.com/v2/books?q=%E6%88%91

中文關鍵字 encode 之後,就成功獲取搜尋到書籍的資料了

note: 這裡不用帶上「-H "Content-Type: application/x-www-form-urlencoded"」
  • curl -d "name=value&name2=value2" 這個方式竟然不用轉換中文字?筆記筆記,再研究看看。
curl -X PATCH -d "ISBN=9981835423" -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' -H "Content-Type: application/x-www-form-urlencoded" https://lidemy-http-challenge.herokuapp.com/v2/books/72

curl -X PATCH -d "name=日好日:茶道教我的幸福15味【電影書腰版】&ISBN=9981835423" -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' -H "Content-Type: application/x-www-form-urlencoded" https://lidemy-http-challenge.herokuapp.com/v2/books/72

以上兩種方式都可以,然後就得到下一關的 token 了。
{"message":"希望之後他們能引進語音輸入系統,我就只要講講話就好。下一關的 token 為 {NeuN}"}

    curl 常用參數:
        -X request
        -H header
        -i include: 顯示 response 的 header
        -d data: 設定 http parameters
        -A, --user-agent STRING  Send User-Agent STRING to server (H)
    

Lv 9 - 自訂的 Header?

  • API 文件裡面有個獲取系統資訊的 endpoint 你記得嗎?
  • 工程師跟我說這個網址不太一樣,用一般的方法是沒辦法成功拿到回傳值的。
  • 想要存取的話要符合兩個條件:
  • 1. 帶上一個 X-Library-Number 的 header,我們圖書館的編號是 20
  • 2. 伺服器會用 user agent 檢查是否是從 Safari 送出的Request,不是的話會擋掉
  • 順利拿到系統資訊之後應該會有個叫做 version 的欄位,把裡面的值放在 query syring 給我吧。
  • 總算來到第九關了
  • curl -X GET -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' -H 'X-Library-Number: 20' https://lidemy-http-challenge.herokuapp.com/v2/sys_info
    
    => Invalid Browser
  • 老招 curl 不能使用,所以我想到的方式是用 fecth 然後用 safari 打開 html
  • // 第九關:用 safari 打開
    fetch("https://lidemy-http-challenge.herokuapp.com/v2/sys_info", {
        headers: {
        Authorization: "Basic YWRtaW46YWRtaW4xMjM=",
        "X-Library-Number": "20"
        }
    }).then(data => {
        console.log(data)
        return data
    }).then(result => {
        console.log(result.json())
    }).catch(err => console.log(err))
  • 看過前輩的心得之後,在爬了一下文,curl 的參數 -A 就可以設定用戶代理了,以下執行後也就成功取得最後一關的線索了。
  • curl -X GET -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15" -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' -H 'X-Library-Number: 20' https://lidemy-http-challenge.herokuapp.com/v2/sys_info
  • 成功獲得下一關的 token
  • 限制這麼多都被你突破了,真有你的。要不要考慮以後來我們圖書館當工程師啊?下一關的 token 為 {duZDsG3tvoA}
  • https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}&num=1256

Lv 10 - GET 之 1A2B

  • 時間過得真快啊,今天是你在這邊幫忙的最後一天了。
  • 我們來玩個遊戲吧?你有玩過猜數字嗎?
  • 出題者會出一個四位數不重複的數字,例如說 9487。
  • 你如果猜 9876,我會跟你說 1A2B,1A 代表 9 位置對數字也對,2B 代表 8 跟 7 你猜對了但位置錯了。
  • 開始吧,把你要猜的數字放在 query string 用 num 當作 key 傳給我。
  • 很多 5566 的彩蛋,不過最大的彩蛋就是跟女友交往前常常玩的 1A2B 了,運氣非常好的第二次就猜中了XD
  • 不過今天發現,數字似乎是隨機的XD

破關!

  • 很開心在這裡的時光能有你一起陪伴,讓我的生活不再那麼一成不變,很開心認識你,下次有機會再一起玩吧!
  • The End,恭喜破關!
  • author: huli@lidemy.com
  • https://www.facebook.com/lidemytw/