---
# System prepended metadata

title: Lidemy HTTP Challenge 過關方式分享 ｜ pcchen

---

# Lidemy HTTP Challenge 過關方式分享 ｜ pcchen
這個小遊戲有好幾種過關的方式，可以在 terminal 用 curl 指令，或者是載 Postman 來用，這兩種方法都很方便、迅速，但因為在 Huli 的 Lidemy 課程中是透過 JavaScript 程式碼，用基礎的方式來理解 API 的串接方式，因此這裡我嘗試用這個方法來撰寫各關的過關攻略，且語法和課程相似，作為上課內容的複習。

## 各關卡攻略

### 第 0 關
- URL: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}
- Method: GET

用JS程式碼前往關卡的方式如下，往後每關只要改 `params` 的 lv? 和 token，因此後面的關卡就不再贅述。
``` javascript=
const request = require('request')
const params = '/lv1?token={GOGOGO}'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
  })
```

### 第 1 關
這一關有兩個重點：
1. 圖書館資訊系統的 API 文件：https://gist.github.com/aszx87410/3873b3d9cbb28cb6fcbb85bf493b63ba
2. 得到 token 的方式為用 GET 回傳 name  

但要過這一關只要先解決第 2 點就好，API 文件在後面關卡才會用到。因此只要先在上一關的 URL 後面新增 `&name=<your name>`，`<your name>` 的地方隨便輸入即可，例如我叫 Doraemon： 

#### JS 程式碼
``` javascript=
const request = require('request')
const params = '/lv1?token={GOGOGO}&name=Doraemon'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 啊...原來你叫 Doraemon 啊！下一關的 token 是 {HellOWOrld}
  })
```
接下來就用這個 token 繼續前往下一關

### 第 2 關
這一關只要直接一個一個套入參數 id 從 54 到 58 ，看哪個可以成功回傳 token。 

- URL:  https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56
- Method: GET

#### JS 程式碼
``` javascript=
const request = require('request')
const params = '/lv2?token={HellOWOrld}&id=56'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 啊！就是這本書，太謝謝你了。下一關的 token 為：{5566NO1}
  })
```

### 第 3 關
這關要新增書籍到圖書資訊系統，因此 URL 要使用圖書系統的網址、Method 是 `POST`，並且要帶有 name 和 ISBN 這兩個資訊。
- URL:  https://lidemy-http-challenge.herokuapp.com/api/books
- Method: POST

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books'

request.post({
    url: 'https://lidemy-http-challenge.herokuapp.com/api' + path,
    form: {
      name: '大腦喜歡這樣學',
      ISBN: '9789863594475'
    }
  },
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // {"message":"新增成功","id":"1989"}
  }
)
```

> 因為這裡只要看結果，就沒有再對 body 作 JSON.parse 的處理了。

把 `id=1989` 參數加到這一關的網址，並用 GET 送出 request 就能得到下一關的 token：
``` javascript=
const request = require('request')
const params = '/lv3?token={5566NO1}&id=1989'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 這樣子讀者就能趕快看到這本新書了，謝謝！下一關的 token 為 {LEarnHOWtoLeArn}
  })
```

### 第 4 關
這一關要**找出所有的書**中，**書名含「世界」兩個字**，且**作者是「村上村樹」** 的書，用程式的邏輯思考就是

**Step 1.** 用 GET 列出所有書籍
**Step 2.** 用 `name.indexOf('世界') >= 0` 判斷書名是否含這兩個字
**Step 3.** 如果也符合 `author === '村上村樹'`，就印出這本書的資訊

- URL:  https://lidemy-http-challenge.herokuapp.com/api/books
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books'

request('https://lidemy-http-challenge.herokuapp.com/api' + path,
  (error, response, body) => {
    if (error) return console.log('err', error)
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    }
    for (let i = 0; i < json.length; i++) {
      if (json[i].name.indexOf('世界') >= 0 && json[i].author === '村上春樹') {
        console.log(json[i])
      }
    }
    // 輸出結果：
    // { id: 79, name: '世界末日與冷酷異境', author: '村上春樹', ISBN: '9571313408' }
    })
```
再用 GET 回傳 `id=79` 就能得到下一關的 token。

```javascript=
const request = require('request')
const params = '/lv4?token={LEarnHOWtoLeArn}&id=79'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 沒錯！這次我很確定了，就是這本！下一關的 token 為 {HarukiMurakami}
  })
```

### 第 5 關
這一關要刪除 id 是 23 的書籍，要用到 DELETE 這個 Method。
- URL:  https://lidemy-http-challenge.herokuapp.com/api/books/23
- Method: DELETE

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books/23'

request.delete('https://lidemy-http-challenge.herokuapp.com/api' + path,
  (error, response, body) => {
    if (error) return console.log('err', error)   
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    } 
    console.log(json.message)
    // 輸出結果：
    // 咦...是刪掉了沒錯，但總覺得哪裡怪怪的，算了，先這樣吧！下一關的 token 為 {CHICKENCUTLET}
  }
)
```
> 做到這裡還以為是我哪裡做錯了嗎？怪怪的是什麼意思？到下一關才知道原來是題目的設計XD
 
### 第 6 關
這一題有新的版本的 URL，比較特別的是這一題還要加入帳號密碼驗證。

首先，要先把帳號密碼做 base64 編碼，我是使用這個[網站](https://www.base64encode.org)。輸入帳號密碼 `admin=admin123` 並點選 ENCODE 後，會得到 `YWRtaW46YWRtaW4xMjM=`。

第二步，將編碼完的結果放進 headers 中。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v2/me
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/me'

request({
    url: ' https://lidemy-http-challenge.herokuapp.com/api/v2' + path,
    headers:{
      'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
    }
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // {"username":"admin","email":"lib@lidemy.com"}
  }
)
```
接下來再將 `lib@lidemy.com` 這個 email 回傳即可得到 token。
```javascript=
const request = require('request')
const params = '/lv6?token={CHICKENCUTLET}&email=lib@lidemy.com'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 對對對，就是這個，這樣才對嘛！下一關的 token 為 {SECurityIsImPORTant}
  })
```

### 第 7 關
這關只需要用新的 API 網址再進行一次資料刪除即可，上一關的帳號密碼認證仍要保留著。
刪除完成，印出內容後即可獲得下一關 token。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v2/books/89
- Method: DELETE

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books/89'

request.delete({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v2' + path,
    headers:{
      'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
    }
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    }
    console.log(json.message)
    // 輸出結果：
    // 希望下一次進這本書的時候不會再被偷走了。下一關的 token 為 {HsifnAerok}
  }
)
```

### 第 8 關
這關要使用到 PATCH，首先要先找出要修改的目標，方法和第四關相似，只是作者的名字改用字串長度判斷。
- URL: https://lidemy-http-challenge.herokuapp.com/api/v2/books
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books'

request({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v2' + path,
    headers:{
      'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
    }
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    }
    for (let i = 0; i < json.length; i++) {
      if (json[i].name.indexOf('我') >= 0 && json[i].author.length === 4) {
        console.log(json[i])
      }
    }
  }
)
```
輸出的內容像這樣：
```
{ id: 3, name: '我殺的人與殺我的人', author: '東山彰良', ISBN: '9262228645' }
{ id: 57, name: '我的櫻花戀人', author: '宇山佳佑', ISBN: '2947749939' }
{
  id: 72,
  name: '日日好日：茶道教我的幸福15味【電影書腰版】',
  author: '森下典子',
  ISBN: '9981835427'
}
```
因此需要修改 ISBN 的就是尾數是 7 且 id 是 72 的這本書，接下來只要用利用 PATCH 將 ISBN 改為 9981835423 即可。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v2/books/72
- Method: PATCH

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/books/72'

request.patch({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v2' + path,
    headers:{
      'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
    },
    form: {
      ISBN: '9981835423'
    }
  },
  (error, response, body) => {
    if (error) return console.log('err', error)  
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    }
    console.log(json.message)
    // 輸出結果：
    // 希望之後他們能引進語音輸入系統，我就只要講講話就好。下一關的 token 為 {NeuN}
  }
)
```

### 第 9 關
這題當初我也卡關很久，上網搜尋後仍對於 User Agent 如何使用很疑惑。後來參考了學長姐的做法後，才知道也同樣是利用在 headers 內新增參數的方法。我們必須在 headers 中加入 `User-Agent` 這個參數，來告訴 API 我們是用 IE6 瀏覽器連線，才能取得資料。

這關要加兩個參數，第一個是題目有敘述到的 `'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='`，第二個則是要先上網搜尋 IE6 的 User-Agent 並放入 headers裡，因此這個參數會像這樣：`'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'`。

> 我是在這個網站上找到資料的：[Internet Explorer User Agents](https://developers.whatismybrowser.com/useragents/explore/software_name/internet-explorer/)

- URL: https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/sys_info'

request({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v2' + path,
    headers:{
      'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
      'X-Library-Number': '20',
      'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'
    },
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    
    let json
    try {
      json = JSON.parse(body)
    } catch (err) {
      console.log(err)
    }
    console.log(json.version)
    // 輸出結果：
    // 1A4938Jl7
  }
)
```
接著再將 version 代碼回傳即可。
```javascript=
const request = require('request')
const params = '/lv9?token={NeuN}&version=1A4938Jl7'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 限制這麼多都被你突破了，真有你的。要不要考慮以後來我們圖書館當工程師啊？下一關的 token 為 {duZDsG3tvoA}
  })
```

### 第 10 關
第 10 關就是單純玩 1A2B 遊戲，只是需要用 GET 傳送 request。假設要猜 1234 這四個數字，發送 request 的方式如下，剩下的純粹就是邏輯遊戲，這邊也不贅述了，猜到數字後就成功拿到第 11 關的 token了。

#### JS 程式碼
```javascript=
const request = require('request')
const params = '/lv10?token={duZDsG3tvoA}&num=1234'

request('https://lidemy-http-challenge.herokuapp.com' + params,
  (error, response, body) => {
    if(error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 0A2B
  })
```

### 第 11 關
在這關有新的 API 網址，先試著將打招呼的 path 用 GET 回傳後，會得到這樣的結果：
```
您的 origin 不被允許存取此資源，請確認您是從 lidemy.com 送出 request。
```
可得知，題目中說的限制就是 request 的來源網址。先偷看一下 hint 寫什麼：
```
伺服器會檢查 origin 這個 header，只要騙過伺服器就行了
```
因此可以知道，解決方法就只要在 headers 中加入 `'origin': 'lidemy.com'`。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v3/hello
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/hello'

request({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v3' + path,
    headers:{
      'origin': 'lidemy.com'
    },
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // Hello! 下一關的 token 為 {r3d1r3c7}
  }
)
```

### 第 12 關
這一題看似只需要採用 /delivery_token 這個 path，但送出後會發現並無法直接得到 token。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v3/delivery_token
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/delivery_token'

request('https://lidemy-http-challenge.herokuapp.com/api/v3' + path,
  (error, response, body) => {
    if (error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 我已經把運送要用的 token 給你囉，請你仔細找找
  }
)
```
這時要注意到題目有一句話非常關鍵：
```
A 到 C，C 才到 B，中間會經過一些轉運點才會到達目的地
```
也就是說，最後 Response 回來的這個結果是經過兩次轉址，因此可以推斷 token 藏在中間經過轉址的這個網址。這部分只跑 JS 程式碼是看不出端倪的，因次改用 DevTools 來看看：

![DevTools](https://i.imgur.com/e6HuiMN.jpg)

可以看到，發送 `deliver_token` 這個 request 網址後，會先轉址到 `stopover`，接著再一次轉址至 `deliver_token_result`。查看 **stopover** 裡的資訊，可以發現在 headers 中有一項 `X-Lv13-Token: {qspyz}`，這個就是這一關的解答了。

### 第 13 關
我們先試著用 `/logs` 這個 path 來看看會發生什麼事。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v3/logs
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/logs'

request('https://lidemy-http-challenge.herokuapp.com/api/v3' + path,
  (error, response, body) => {
    if (error) return console.log('err', error)
    console.log(body)
    // 輸出結果：
    // 此 request 不是來自菲律賓，禁止存取系統資訊。
  }
)
```
再看一下 hint 說什麼：
```
你有聽過代理伺服器 proxy 嗎？
```
因此可推測，應是要使用 proxy 來偽裝 request 的伺服器來源是在菲律賓。上網用「proxy 菲律賓」這個關鍵字搜尋後，找到這個[網站](http://free-proxy.cz/zh/proxylist/country/PH/https/ping/all)，並且選擇 協定為 https 的 IP 來當作代理伺服器。
若是使用 MacBook，設定代理伺服器的步驟為：`系統偏好設定 ＞ 網路 ＞ 進階 ＞ 代理伺服器`，勾選`安全網頁代理伺服器（HTTPS）`後，填入 IP 位址與 Port。

![Proxy](https://i.imgur.com/0qWOMdy.jpg)

接下來直接在網址列輸入前往 `https://lidemy-http-challenge.herokuapp.com/api/v3/logs`，就可得到結果。
```
[
 { logType: 'token', value: '{SEOisHard}' }
]
```

### 第 14 關
這一關老實說我只看題目覺得有點理解不能，因此馬上查看 hint XD
```
伺服器是怎麼辨識是不是 Google 搜尋引擎的？仔細想想之前我們怎麼偽裝自己是 IE6 的
```
由這個提示可以聯想到第 9 關的 **User-Agent**。因此只需要上網用「Google User-Agent」查詢一下就能得到答案，示範如下。

- URL: https://lidemy-http-challenge.herokuapp.com/api/v3/index
- Method: GET

#### JS 程式碼
```javascript=
const request = require('request')
const path = '/index'

request({
    url: 'https://lidemy-http-challenge.herokuapp.com/api/v3' + path,
    headers:{
      'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
    },
  },
  (error, response, body) => {
    if (error) return console.log('err', error)
    console.log(body)
  }
)

```
得到輸出結果後就拿到最後一關的 token 了，第 15 關沒有內容，到這邊基本上就大功告成了！

## 破關心得分享
非常感謝 Huli 老師用心地設計這個遊戲，這是一個很好的方式去把基本 API 的內容走過、複習過一遍，因為題目的敘述真的都很有趣，會讓人想一關接著一關的玩下去。同時，也練習到用 Postman 和 Curl（雖然我這裡只寫老師上課教到的 JS 程式碼方法），有許多同學在最後心得分享提到可以用這兩個工具輕鬆破關，試了一次後發現這兩種工具確實非常簡便，但同時也慶幸我第一次完成是採用土法煉鋼的方法，因為對於 API 如何用程式操作有更進一步的了解。

第一次坐覺得比較困難的地方是 headers 裡面要放的參數，像第 9 關設定 User-Agent 這裡卡比較久，原本以為這是一個網頁的設定之類的，後來知道是放在 headers 裡面後，在解後面的關卡時就比較有感覺哪些東西可能也是要被放在 headers 裡面。

這篇破關攻略是第二次邊實作邊寫下來的，畢竟第一次在卡關的時候有上網去找過去學長姐的分享，第二次完全靠自己力量再做一次，並同時以筆記方式寫下，藉此加深印象。