前言
這是 Huli 大大做的一個有趣的 http 遊戲,可以藉由這個遊戲更加了解 http 的各項知識,建議先了解基礎知識再來解題會比較知道在幹嘛,可以參考我之前的筆記 網路的本質其實沒有你想的那麼難 和 最熟悉的陌生人:API。
那廢話不多說,就馬上開始吧!
.
.
.
.
以下為我的解題心得,有雷慎入
.
.
.
.
.
Lv0
這邊只是介紹這個遊戲,所以靠著這邊的提示,就可以到第一關。
lv1
https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}
這邊有提供一個串接 API 的文件,但這邊不會用到:API 文件
一樣是依照描述把 name 帶上,這邊就看你叫什麼就打什麼
https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=Derek
lv2
https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}
這邊我是從 54~58之間一個一個試的
https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56
lv3
https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}
這關就要利用到剛剛的 API 文件
因為這邊會用到 POST 這個 method,而文件上也說了如果使用 POST,他的 content type 是 application/x-www-form-urlencoded。
意思就是如果你要傳資料給他的話,必須符合 application/x-www-form-urlencoded 的格式傳送(這邊因為使用 request 這個 library,所以要按照這個格式),其他常見格式還有 multipart/form-data、application/json等。
確認好格式之後就可以來新增了,POST 成功印出 body 會得到 {"message":"新增成功","id":"1989"}
完整程式碼如下:
const request = require('request');
request.post(
'https://lidemy-http-challenge.herokuapp.com/api/books',
{form:{
name: '《大腦喜歡這樣學》',
ISBN: '9789863594475'
}},
(err, response, body) => {
console.log(body)
}
)
把得到的 id 帶上網址就是答案了!
https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}&id=1989
*這邊要補充的是,前面有說到 content type,他是放在 headers 裡的資訊。當 server 告訴你要使用 application/x-www-form-urlencoded 的格式傳送資料,而你也用相應的格式帶上了:
form:{ name: '123', ISBN: 456 }
透過編碼,就會透過這個格式產生像這樣的資料放在 body 裡
body: 'name=123&ISBN=456'
而 server 接收到這個 request 後才能做相對應的動作,但如果你給了不正確或不符合的格式,server 端就會看不懂,造成錯誤。*另外,這樣的格式要小心的地方是,他可能輸出的跟你想的不一樣,什麼意思呢?
form:{ name: '123', ISBN: 'a&b=1' }
假設你帶上這樣的資訊,它在轉換時就會變成
name=123&ISBN=a&b=1
,是不是發現問題了。
x-www-form-urlencoded 最後面的 urlencoded 就是編碼的意思,我們必須使用編碼的方式,把它轉換成別種形式,才可以避免混淆。
所以這邊可以用encodeURIComponent('a&b=1')
,編碼完成再帶入。因為帶入的資訊是動態的,所以通常我們會都經過編碼後再帶入資訊。
lv4
https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}
這邊要你使用獲取所有書籍,並且後面帶入查詢書籍的參數,所以直覺的就寫成以下:
const request = require('request');
request.get(
'https://lidemy-http-challenge.herokuapp.com/api/books?q=世界',
(err, response, body) => {
console.log(body)
}
)
不過這時候會跳出報錯的訊息,TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters
,表示使用 get 或 post 的方式發 request 到後台,且 url 中包含中文。
為了解決這個問題,便利用 encodeURI()
將中文字串轉為 UTF-8 編碼
const request = require('request');
const str = encodeURI('世界')
request.get(
`https://lidemy-http-challenge.herokuapp.com/api/books?q=${str}`,
(err, response, body) => {
console.log(body)
}
)
這樣便可以印出所有書名包含『世界』的書了。
根據線索就會知道是 id = 79 的『世界末日與冷酷異境』
https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}&id=79
lv5
https://lidemy-http-challenge.herokuapp.com/lv5?token={HarukiMurakami}
*這邊的 token 就是村上春樹(Haruki Murakami)
照著文件做還滿簡單的
const request = require('request');
request.delete(
'https://lidemy-http-challenge.herokuapp.com/api/books/23',
(err, response, body) => {
console.log(body)
}
)
成功刪除後就會印出答案,{"message":"\n咦...是刪掉了沒錯,但總覺得哪裡怪怪的,算了,先這樣吧!下一關的 token 為 {CHICKENCUTLET}\n"}
lv6
https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}
這邊拿到一個新文件:新文件
這關主要是要你將資訊放入 request 的 header 中,但這組帳密要以 base64 編碼後的形式帶入,所以就隨便找一個線上可以轉換的即可(提示:Encode to Base64 format)
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/me',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
}
function callback (error, response, body) {
console.log(body)
}
request(option, callback)
便可以得到 {"username":"admin","email":"lib@lidemy.com"}
按照題目指示放入 query string 中即可。
https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}&email=lib@lidemy.com
lv7
https://lidemy-http-challenge.herokuapp.com/lv7?token={SECurityIsImPORTant}
這關一樣是按照文件,滿簡單的
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/89',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
}
function callback (error, response, body) {
console.log(body)
}
request.delete(option, callback)
最後就會印出 {"message":"\n希望下一次進這本書的時候不會再被偷走了。下一關的 token 為 {HsifnAerok}\n"}
lv8
https://lidemy-http-challenge.herokuapp.com/lv8?token={HsifnAerok}
這題一樣是先查詢書籍
const request = require('request');
const str = encodeURI('我')
const option = {
url: `https://lidemy-http-challenge.herokuapp.com/api/v2/books?q=${str}`,
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
}
function callback (error, response, body) {
const json = JSON.parse(body)
console.log(json)
}
request.get(option, callback)
藉由印出的資訊可以知道,就是 id = 72 的這本書
接下來要做的就是更新資料了
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/72',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
},
form: {
ISBN: '9981835423',
}
}
function callback (error, response, body) {
console.log(body)
}
request.patch(option, callback)
成功更新資料後就會印出訊息 {"message":"\n希望之後他們能引進語音輸入系統,我就只要講講話就好。下一關的 token 為 {NeuN}\n"}
lv9
https://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}
這邊說要獲取系統資料要符合兩個條件:
- 第一個條件很簡單,key & value 都給你了
- 第二個條件有點卡關,之後利用 devtool > network,去檢查 request header,可以看到裡面有 User-Agent 這一項(user agent 指的是你透過什麼來幫你發送 request),接著用關鍵字去找 IE6 的 user agent 要打什麼。
找到了這個,剛開始只輸入了 Mozilla/4.0,結果印出Invalid Browser
,還想說是不是搞錯方向了,原來是整串都要輸入。
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'X-Library-Number': '20',
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'
},
}
function callback (error, response, body) {
console.log(body)
}
request.get(option, callback)
成功印出 {"message":"success","version":"1A4938Jl7","owner":"lib","createdAt":"121290329301"}
最後把 version 的值放入 query string 就可以了!
https://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}&version=1A4938Jl7
lv10
https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}
這一關是猜數字,真是懷念XD
就按照給的提示很快就找到答案摟
https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}&num=9613
原本應該是最後一關了,但 Huli 似乎又增加了新關卡,之後有空再來玩玩!
lv11
https://lidemy-http-challenge.herokuapp.com/lv11?token={IhateCORS}
這邊提供一份新的 API 文件
按照文件的方法打招呼果然有限制
const request = require('request');
request.get(
'https://lidemy-http-challenge.herokuapp.com/api/v3/hello',
(error, response, body) => {
console.log(body)
}
)
印出了 您的 origin 不被允許存取此資源,請確認您是從 lidemy.com 送出 request。
所以將 Origin 放進去
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v3/hello',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'Origin': 'lidemy.com'
},
}
function callback (error, response, body) {
console.log(body)
}
request.get(option, callback)
果然這樣就 OK 了!
lv12
https://lidemy-http-challenge.herokuapp.com/lv12?token={r3d1r3c7}
按照文件實作
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v3/deliver_token',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'Origin': 'lidemy.com'
},
}
function callback (error, response, body) {
console.log(body)
}
request.get(option, callback)
果然沒這麼簡單,印出了 我已經把運送要用的 token 給你囉,請你仔細找找
。
按照題目的提示,這裡應該要去看網頁經過了哪些轉址,再從裡面找線索。
打開 devtool > network,在網址列輸入 https://lidemy-http-challenge.herokuapp.com/api/v3/deliver_token
後可以看到,網頁會依序經過:
- deliver_token
- stopover
- deliver_token_result
而在 deliver_token 和 stopover 的 response header 中都有 X-Lv13-Token,利用這個參數就可以過關啦!
lv13
https://lidemy-http-challenge.herokuapp.com/lv13?token={qspyz}
按照 API 文件
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v3/logs',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'Origin': 'lidemy.com',
},
}
function callback (error, response, body) {
console.log(body)
}
request.get(option, callback)
會印出訊息 此 request 不是來自菲律賓,禁止存取系統資訊。
這邊帶入參數 &hint=1
去看了提示,關鍵字是 proxy。
這邊去到 Chrome 的設定 > 開啟電腦的 proxy 設定 > Mac 會跳轉到網路的代理伺服器設定,這邊會需要輸入 proxy,所以就在網路上隨便搜一組 http 的 proxy,然後把 IP address & port 貼過來即可(記得 http 那一欄要打勾)。
最後把網址貼上 https://lidemy-http-challenge.herokuapp.com/api/v3/logs
,即可得到下一關的 token。
[
{ logType: 'token', value: '{SEOisHard}' }
]
lv14
https://lidemy-http-challenge.herokuapp.com/lv14?token={SEOisHard}
看完還是不知道在幹嘛XD,一樣直接看提示:
伺服器是怎麼辨識是不是 Google 搜尋引擎的?仔細想想之前我們怎麼偽裝自己是 IE6 的
哦哦原來要用 lv9 時用過的 User-Agent,下關鍵字 user agent google search 就可以找到了:Googlebot User Agents,第一個就是。
程式碼如下:
const request = require('request');
const option = {
url: 'https://lidemy-http-challenge.herokuapp.com/api/v3/index',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'Origin': 'lidemy.com',
'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
},
}
function callback (error, response, body) {
console.log(body)
}
request.get(option, callback)
就會印出最終的答案了!
token for lv15:{ILOVELIdemy!!!}
lv15
https://lidemy-http-challenge.herokuapp.com/lv15?token={ILOVELIdemy!!!}
這樣就破關溜,這裏 Huli 也開了一個 gist 讓大家留言XDD
這個小遊戲好玩又讓我學到很多,雖然中間有些地方真的卡了很久,不過拿到 token 時就是爽,有興趣可以不看解答先玩玩看喔~