HackMD
    • Create new note
    • Create a note from template
    • Sharing Link copied
    • /edit
    • View mode
      • Edit mode
      • View mode
      • Book mode
      • Slide mode
      Edit mode View mode Book mode Slide mode
    • Customize slides
    • Note Permission
    • Read
      • Only me
      • Signed-in users
      • Everyone
      Only me Signed-in users Everyone
    • Write
      • Only me
      • Signed-in users
      • Everyone
      Only me Signed-in users Everyone
    • Commenting & Invitee
    • Publishing
      Please check the box to agree to the Community Guidelines.
      Everyone on the web can find and read all notes of this public team.
      After the note is published, everyone on the web can find and read this note.
      See all published notes on profile page.
    • Commenting Enable
      Disabled Forbidden Owners Signed-in users Everyone
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Invitee
    • No invitee
    • Options
    • Versions and GitHub Sync
    • Transfer ownership
    • Delete this note
    • Note settings
    • Template
    • Save as template
    • Insert from template
    • Export
    • Dropbox
    • Google Drive Export to Google Drive
    • Gist
    • Import
    • Dropbox
    • Google Drive Import from Google Drive
    • Gist
    • Clipboard
    • Download
    • Markdown
    • HTML
    • Raw HTML
Menu Note settings Sharing Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Transfer ownership Delete this note
Export
Dropbox Google Drive Export to Google Drive Gist
Import
Dropbox Google Drive Import from Google Drive Gist Clipboard
Download
Markdown HTML Raw HTML
Back
Sharing
Sharing Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Comment & Invitee
Publishing
Please check the box to agree to the Community Guidelines.
Everyone on the web can find and read all notes of this public team.
After the note is published, everyone on the web can find and read this note.
See all published notes on profile page.
More (Comment, Invitee)
Commenting Enable
Disabled Forbidden Owners Signed-in users Everyone
Permission
Owners
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Invitee
No invitee
   owned this note    owned this note      
Published Linked with GitHub
Like BookmarkBookmarked
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# API 基礎 ###### tags: `Tag(網路基礎)` `Tag(API)` ### API 是什麼? >[參考資料](https://blog.techbridge.cc/2017/05/20/api-ajax-cors-and-jsonp/) 輕鬆理解 Ajax 與跨來源請求 :::success 就像是自動販賣機的==按鈕/面版== 可口可樂公司的商品中有各類可樂飲料 1.今天你想取得一瓶原味可樂 2.只要單純的按下==面版上==原味可樂的 ==按鈕== 3.接著你就可以在取物口拿到一瓶可樂 上面第二個動作中的==面版/按鈕, 就是所謂的 API== 了 ==透過這個面版, 你可以拿到可口可樂公司的飲料== 過程大概就是: ``` - 想要一瓶可樂(想要的資料) - 按下按鈕(送出資料需求) - 拿到飲料(取得資料) ``` ::: >[參考資料](https://cola.workxplay.net/what-is-an-api/) 什麼是API? >[參考資料](https://medium.com/@hulitw/ramen-and-api-6238437dc544) 從拉麵店的販賣機理解什麼是 API 全名為 Application Programming Interface,中文翻譯為「應用程式==介面==」 >簡單來說就是==方便溝通、交換資料的管道==。 API 有分很多種: :::success ``` * 軟硬體廠商的 API * 有作業系統用的 API ,用於傳輸、寫入、讀取資料…等等電腦上一切的操作 * 自己團隊內部用的 API * 對於網頁來說就是 Web API 是基於 http 協定下運作的 API ``` ::: --- ### 什麼是 JSON 格式資料? >[參考資料](https://www.footmark.info/programming-language/javascript/json-format-and-javascript/) JSON 格式與 JavaScript 解析教學範例 #### JSON 格式 JSON 檔案具備了鍵`(Key)`與值`(Value)` ###### ==`JSON 字串`== `可以包含 object (物件) 或 array (陣列) 資料` ``` JS { "number": "1020501", "name": "小傑", "age": 32, "sex": "M", "interest": [ "網頁設計", "撰寫文章" ] } ``` #### 如何載入 JSON 檔案 ==**串接API的本質就是交換資料**== --- ### JavaScript 處理 JSON >[參考資料](https://www.footmark.info/programming-language/javascript/json-format-and-javascript/) JSON 格式與 JavaScript 解析教學範例 ###### `JavaScript物件` ``` js {name: 'Renee',isTall: true} ``` ###### `JSON 格式的字串` 物件的屬性名name,==在JSON中被引號包起來變成'name'==,也就是說==原本的屬性名到了JSON變成字串== ``` js {'name':'Jen','isTall':'true'} ``` ###### `JavaScript物件 & JSON 格式的字串 一起印出來比對` ![](https://i.imgur.com/RUHaNEE.png) ![](https://i.imgur.com/LFXJWTg.png) #### `物件與JSON字串的轉換,有兩個重要函式` ==`JSON.stringify()`== 可以 ==將 `JavaScript` 物件序列化成 `JSON` 字串== 第二個參數 可以是 是一個 function 或是 一個 array 第三個參數,來控制結果字串的縮排間距,並會自動換行 ```javascript= // JavaScript 物件 var member = { "number": "1020501", "name": "小傑", "age": 32, "sex": "M", "interest": [ "網頁設計", "撰寫文章" ] }; // 使用第二個參數 function 方式,排除 age 特性不被序列為 JSON 字串 console.log( JSON.stringify(member, function(key, value) { if (key === "age") return undefined; return value; }) ); ``` ![](https://i.imgur.com/9JbsbTD.png) ==`JSON.parse()`== 方法可以將 `JSON` 字串 ==解析成 `JavaScript` 物件== ,這樣就可使用 `JavaScript` 進行操作了 第二個參數 function 用來轉換解析出的屬性值,return 的值決定最後在物件上的特性值 ```javascript= // 宣告字串須使用 `` 包起來 var jsonString = `{ "number": "1020501", "name": "小傑", "age": 32, "sex": "M", "interest": [ "網頁設計", "撰寫文章" ] }`; // 使用第二個參數 function 方式,排除 age 特性不被包括在物件 var member = JSON.parse(jsonString, function(key, value) { if (key === "age") return undefined; return value; }); // 取得物件 console.log(member); ``` ![](https://i.imgur.com/pnyMmBG.png) >[參考資料](https://www.tutorialspoint.com/proper-way-to-catch-exception-from-json-parse) Proper way to catch exception from JSON.parse >[參考資料](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript) The 80/20 Guide to JSON.stringify in JavaScript >[參考資料](https://www.digitalocean.com/community/tutorials/js-json-parse-stringify) JSON.parse() and JSON.stringify() ###### `try…catch 語法使用` 可以==在程式執行可能拋出錯誤的地方使用==,主動捕捉並處理錯誤,==避免整個程式因為發生錯誤而停止執行。== ``` js try { // 預期可能會發生錯誤的程式碼 } catch (e) { // try 區塊有拋出錯誤時,則執行這裡的程式碼 } finally { // finally 區塊的程式碼一定會在最後被執行 // 可以省略 finally 區塊 } ``` ```javascript= function validateData(jsonData){ let data try{ data = JSON.parse(jsonData); } catch(e) { console.log('Error data', e) data = null } return data } console.log(validateData('[1, 5, "false"]')) console.log(validateData('1, 11')) //null ``` ![](https://i.imgur.com/6X24vmA.png) >[參考資料](https://pjchender.blogspot.com/2017/12/js-error-handling.html) 談談 JavaScript 中的錯誤處理 Error Handling >[參考資料](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part3/error.html) 錯誤與例外處理 --- API 文件通常都不會給出完整網址,因為絕大多數 API 其實都是透過==兩個部分所組成== - Base URL - 不同的 path ###### `範例1 串接API,執行後會列出前十本書籍的 id 以及書名` >[參考資料](https://tigercosmos.xyz/post/2018/11/master_js/object/) 30 天 Javascript 從入門到進階:物件 >[參考資料](https://wcc723.github.io/javascript/2017/12/22/javascript-template-string/) JavaScript Template String 樣板字串 >[color=#ff0cc6][參考資料](https://www.jishuwen.com/d/2GBN/zh-tw) 正確配置 Visual Studio Code 開發和除錯 TypeScript `Base URL`: `https://lidemy-book-store.herokuapp.com` ![](https://i.imgur.com/j2Kku7Y.png) ###### `學習看request文件` >[文件連結](https://github.com/request/request#custom-http-headers) ![](https://i.imgur.com/SXWnSnh.png) ```javascript= // 引入了request的library const request = require('request'); // 抓取 url 的內容 request.get({ url: 'https://lidemy-book-store.herokuapp.com/books?_limit=10', }, (error, reponse, body) => { let data; try { data = JSON.parse(body); // 用 JSON.parse處理JSON格式的字串 } catch (error) { console.log('error'); } for (let i = 0; i < data.length; i++) { //ES6 新語法 Template Literals:使用 ${ } 來加入變數或函式 //使用 ${ data[i].id } 來插入變數 console.log(`${data[i].id} ${data[i].name}`) } } ); ``` ###### `範例2 串接API,可以手動加入參數後顯示前 20 本書的資料、刪除、新增以及修改書本` >[參考資料](https://www.fooish.com/javascript/switch-case.html) JavaScript switch 語法 >[參考資料](https://www.footmark.info/programming-language/php/ajax-javascript-jquery-example-php/) AJAX JavaScript 與 jQuery 教學範例 for PHP ###### `學習看request文件` >[文件連結](https://github.com/request/request#custom-http-headers) ![](https://i.imgur.com/8zLx8wP.png) `Base URL`: `https://lidemy-book-store.herokuapp.com` :::success 小補充 : `process` 模組 `process` 是 `Node.js` 內建的模組,功能為「 ==取得指令的參數== 」。 - 引入: `const process = require('process')` - 拿使用者下的參數: ==`process.argv`== ::: ###### `印出process.argv 觀察使用方法` ``` js console.log(process.argv) ``` 會發現印出來的==是一個陣列==,[arr[0]](第一個元素)是 node、 [arr[1]](第二個元素)是 server.js ,[arr[2]](第三個元素)可以得到 我們要的內容。 結論:使用`process.argv` 會==從[arr[2]](第三個元素)開始使用== :`process.argv[2]` ![](https://i.imgur.com/gAk8WQ3.png) ```javascript= // 顯示前 20 本書的資料、刪除、新增以及修改書本 // 串接API // 引入了request的library const request = require('request'); // 讀取使用者下的參數 const args = process.argv; const apiUrl = 'https://lidemy-book-store.herokuapp.com'; const action = args[2]; const params = args[3]; // ES6 新語法 Template Literals:使用 ${ } 來加入變數或函式 // 使用 ${ apiUrl } 來插入變數 function listBooks() { // eslint-disable-next-line consistent-return request(`${apiUrl}/books?_limit=20`, (error, response, body) => { if (error) { // eslint-disable-next-line no-console return console.log('讀取資料失敗', error); } const data = JSON.parse(body); for (let i = 0; i < data.length; i += 1) { // eslint-disable-next-line no-console console.log(`${data[i].id} ${data[i].name}`); } }); } function readBook(id) { // eslint-disable-next-line consistent-return request(`${apiUrl}/books/${id}`, (error, response, body) => { if (error) { // eslint-disable-next-line no-console return console.log('讀取資料失敗', error); } const data = JSON.parse(body); // eslint-disable-next-line no-console console.log(data); }); } function deleteBook(id) { // eslint-disable-next-line consistent-return request.delete(`${apiUrl}/books/${id}`, (error) => { if (error) { // eslint-disable-next-line no-console return console.log('刪除失敗', error); } // eslint-disable-next-line no-console console.log('刪除成功!'); }); } function createBook(name) { request.post({ url: `${apiUrl}/books`, form: { name, }, // eslint-disable-next-line consistent-return }, (error) => { if (error) { // eslint-disable-next-line no-console return console.log('新增失敗', error); } // eslint-disable-next-line no-console console.log('新增成功!'); }); } function updateBook(id, name) { request.patch({ url: `${apiUrl}/books/${id}`, form: { name, }, // eslint-disable-next-line consistent-return }, (error) => { if (error) { // eslint-disable-next-line no-console return console.log('更新失敗', error); } // eslint-disable-next-line no-console console.log('更新成功!'); }); } // switch 語法 // 變數的值是 list,則會執行 case 'list': listBooks();區塊的程式碼 switch (action) { case 'list': listBooks(); break; case 'read': readBook(params); break; case 'delete': deleteBook(params); break; case 'create': createBook(params); break; case 'update': updateBook(params, args[4]); break; default: // eslint-disable-next-line no-console console.log('Available commands: list, read, delete, create and update'); } ``` ###### `範例3 串接API,輸入國家的英文名字,就能夠查詢符合的國家的資訊` >[參考資料](https://www.footmark.info/programming-language/php/ajax-javascript-jquery-example-php/) AJAX JavaScript 與 jQuery 教學範例 for PHP >[參考資料](https://tigercosmos.xyz/post/2018/11/master_js/object/) 30 天 Javascript 從入門到進階:物件 >[參考資料](https://wcc723.github.io/javascript/2017/12/22/javascript-template-string/) JavaScript Template String 樣板字串 ###### `學習看API文件` >[文件連結](https://restcountries.eu/#api-endpoints-name) ![](https://i.imgur.com/RLmhG7Z.png) ![](https://i.imgur.com/H0RLlsz.png) ```javascript= // 輸入國家的英文名字,就能夠查詢符合的國家的資訊 // 引入了request的library const request = require('request'); // 讀取使用者下的參數 const args = process.argv; const apiUrl = 'https://restcountries.eu/rest/v2'; const name = args[2]; // ES6 新語法 Template Literals:使用 ${ } 來加入變數或函式 // 使用 ${ apiUrl } 來插入變數 // eslint-disable-next-line request(`${apiUrl}/name/${name}`, (error, response, body) => { if (error) { return console.log('讀取資料失敗', error); } // 用 JSON.parse處理JSON格式的字串 // eslint-disable-next-line let data = JSON.parse(body); // status 請求回應狀態,也就是 HTTP 狀態碼(status code) // 4xx:客戶端錯誤 表示客戶端提交的請求中有錯誤或者不能被完成 if (data.status >= 400 && data.status < 500) { return console.log('找不到國家資訊'); } // node hw3.js korea // args[2] 需要是國家名稱 if (!name) { return console.log('請輸入國家名稱'); } for (let i = 0; i < data.length; i += 1) { console.log('========================'); // ES6 新語法 Template Literals:使用 ${ } 來加入變數或函式 // 使用 ${ data[i].id } 來插入變數 console.log(`國家: ${data[i].name}`); console.log(`首都: ${data[i].capital}`); console.log(`貨幣: ${data[i].currencies[0].code}`); console.log(`國碼: ${data[i].callingCodes[0]}`); } }); ``` ###### `範例4 串接API,呼叫 Twitch API,並拿到「最受歡迎的遊戲列表(Get Top Games)」` ###### `依序印出目前觀看人數跟遊戲名稱` >[參考資料](https://www.footmark.info/programming-language/php/ajax-javascript-jquery-example-php/) AJAX JavaScript 與 jQuery 教學範例 for PHP >[參考資料](https://ithelp.ithome.com.tw/articles/10192541) 突發任務:Twitch API >[參考資料](https://blog.huli.tw/2017/08/27/ajax-and-cors/) 輕鬆理解 Ajax 與跨來源請求 >[參考資料](https://pjchender.blogspot.com/2017/01/javascript-es6-for-of.html) JavaScript ES6 中的 for ... of(處理陣列的好幫手) >[參考資料](https://tigercosmos.xyz/post/2018/11/master_js/object/) 30 天 Javascript 從入門到進階:物件 ###### `學習看request文件` >[文件連結](https://github.com/request/request#custom-http-headers) ![](https://i.imgur.com/KTdgjTp.png) ###### `學習看API文件` >[文件連結](https://dev.twitch.tv/docs/v5) >[文件連結](https://dev.twitch.tv/docs/v5/reference/games) ###### ==`在 request header 中帶上 ClientID 跟另一個參數 Accept`== ![](https://i.imgur.com/M5E8WiE.png) ###### ==`從API文件觀察 如何取得baseUrl`== ![](https://i.imgur.com/jomB4qU.png) ###### ==`從API文件觀察 如何取得目前觀看人數跟遊戲名稱的資料`== ![](https://i.imgur.com/uhopx1y.png) ```javascript= // 呼叫 Twitch API,並拿到「最受歡迎的遊戲列表(Get Top Games)」 // 依序印出目前觀看人數跟遊戲名稱 // 引入了request的library const request = require('request'); // Twitch developer dashboard 註冊一個新的 Application 會拿到一個 ClientID const clientID = 'br15dzlr0ukquy97xhv00y3i9r9g4x'; const baseUrl = 'https://api.twitch.tv/kraken'; request({ method: 'GET', //拿到「最受歡迎的遊戲列表(Get Top Games)」 url: `${baseUrl}/games/top`, headers: { 'Client-ID': clientID, 'Accept': 'application/vnd.twitchtv.v5+json' } }, function(error,response,body){ if(error){ return console.log(error) } // 用 JSON.parse處理JSON格式的字串 const data = JSON.parse(body) const games = data.top //ES6 語法 for...of //可以把陣列的值一個個取出 for(let game of games) { //用 . 來取得物件的資料 console.log(game.viewers + ' ' + game.game.name) } }) ``` --- ### `Lidemy HTTP Challenge` ###### `第一關` 用 `GET` 方法跟圖書館管理員`lib` 說我的名字 ```javascript= const request = require('request'); request.get( { // 把名字傳給lib url: 'https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=ruofan', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/OFBborn.png) ###### `第二關` 幫`lib`找一本書 >[API文件](https://gist.github.com/aszx87410/3873b3d9cbb28cb6fcbb85bf493b63ba) ```javascript= const request = require('request'); request.get( { // 從api文件取得書籍得資料 url: 'https://lidemy-http-challenge.herokuapp.com/api/books/56?token={HellOWOrld}&id=56', // 再傳給lib url: 'https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/PzuI4ag.png) ###### `第三關` ```javascript= const request = require('request'); request.post( { url: 'https://lidemy-http-challenge.herokuapp.com/api/books?token={5566NO1}', form: { name: '大腦喜歡這樣學', ISBN: '9789863594475', }, }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); request.get( { // 把名字傳給lib url: 'https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}&id=1989', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/H5fVL9e.png) ###### `第四關` >[參考資料](https://ithelp.ithome.com.tw/articles/10201503) Postman - 測試 API 神器 1/2 >[參考資料](https://pjchender.github.io/2018/08/31/guide-%E4%BD%BF%E7%94%A8-js-%E8%A7%A3%E6%9E%90%E7%B6%B2%E5%9D%80%E8%88%87%E8%99%95%E7%90%86%E7%B6%B2%E5%9D%80%E4%B8%AD%E7%9A%84%E5%8F%83%E6%95%B8%EF%BC%88url-parameters%EF%BC%89/) 使用 JS 解析網址與處理網址中的參數(URL Parameters) >[API文件](https://gist.github.com/aszx87410/3873b3d9cbb28cb6fcbb85bf493b63ba) ###### `解法` ###### 使用 `encodeURI()` ==轉換網址== `Base URL`: `https://lidemy-http-challenge.herokuapp.com/api` ```javascript= const request = require('request'); let str = '世界'; let uri = encodeURI(`https://lidemy-http-challenge.herokuapp.com/api/books?q=${str}`); request.get(uri, function (error, response, body) { console.log(JSON.parse(body)); }); ``` ![](https://i.imgur.com/4dSfO5r.png) ###### `postman` 使用`postman`找到書名含有『世界』的書,`id:79`即是我們要的那一本! ![](https://i.imgur.com/uNRmRhh.png) ``` js [{"id":2,"name":"當我想你時,全世界都救不了我","author":"肆一","ISBN":"5549173495"},{"id":27,"name":"從你的全世界路過","author":"張嘉佳","ISBN":"8426216529"},{"id":79,"name":"世界末日與冷酷異境","author":"村上春樹","ISBN":"9571313408"},{"id":90,"name":"文學的40堂公開課:從神話到當代暢銷書,文學如何影響我們、帶領我們理解這個世界","author":"約翰.薩德蘭","ISBN":"7978376866"}] ``` ```javascript= const request = require('request'); request.get( { // 從api文件取得書籍得資料 url: 'https://lidemy-http-challenge.herokuapp.com/api/books/79?token={LEarnHOWtoLeArn}&id=79', // 再傳給lib url: 'https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}&id=79', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/N7mv33k.png) ###### `第五關` 幫忙刪除`id:23`的書 ```javascript= const request = require('request'); request.delete( { // 從api文件取得書籍得資料 url: 'https://lidemy-http-challenge.herokuapp.com/api/books/23?token={HarukiMurakami}&id=23', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/uVKCCmB.png) ###### `第六關` >[API文件](https://gist.github.com/aszx87410/1e5e5105c1c35197f55c485a88b0328a) >[BASE64編碼器](https://www.ez2o.com/App/Coder/Base64) >[參考資料](https://ithelp.ithome.com.tw/articles/10185699?sc=pt) 小白合送的土耳其絨毯- Http Basic Authentication >[參考資料](https://matthung0807.blogspot.com/2019/11/java-string-base64-encode-decode.html) Java String Base64 編碼(Encode)及解碼(Decode) >[參考資料](https://carsonwah.github.io/http-authentication.html) HTTP認證(HTTP Authentication) ###### `Node.js 可使用` ==Buffer.from() 進行 base64 編碼== >`關鍵字 http basic authorization` ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); //console.log(base64Str); request.get( { url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/me', url: 'https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}&email=lib@lidemy.com', headers: { 'Authorization': `Basic ${base64Str}` } }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/GDbncG8.png) ###### ==`HTTP Basic`== ###### `編碼前` ``` js Authorization: Basic base64(admin:admin123) ``` > [color=#ff9a76]使用 [BASE64編碼器](https://www.ez2o.com/App/Coder/Base64) 轉換 ###### `編碼後` ``` js Authorization: Basic YWRtaW46YWRtaW4xMjM= ``` ###### ` postman` ###### `驗證方法為傳入 Authorization 的 Header` >`base API`: `https://lidemy-http-challenge.herokuapp.com/api/v2/me` ![](https://i.imgur.com/M1IJ5PT.png) ![](https://i.imgur.com/HvFFXfx.png) ###### `將 email 放在 queryString` ```javascript= const request = require('request'); request.get( { url: 'https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}&email=lib@lidemy.com', }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/GDbncG8.png) ###### `第七關` ###### 刪除一本書 `id:89` ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); //console.log(base64Str); request.delete( { url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/89', headers: { 'Authorization': `Basic ${base64Str}` } }, (error, response, body) => { // eslint-disable-next-line no-console console.log(body); }, ); ``` ![](https://i.imgur.com/OUcAmNs.png) ###### `postman` ###### `一樣是 DELETE 方法,不同的是,這次要加上剛剛的 Authorization` ![](https://i.imgur.com/euX9QOT.png) ###### `第八關` 查詢書名含有『我』的書籍 ###### 使用 `encodeURI()` ==轉換網址== ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); let queryStr = '我'; let uri = encodeURI(`https://lidemy-http-challenge.herokuapp.com/api/v2/books?q=${queryStr}`); request.get( { uri, headers: { 'Authorization': `Basic ${base64Str}` } }, (error, response, body) =>{ console.log(JSON.parse(body)); }, ); ``` ![](https://i.imgur.com/qTIu1f1.png) ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); request.patch( { url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/72', contentType: 'application/x-www-form-urlencoded', headers: { 'Authorization': `Basic ${base64Str}` }, form: { name: '日日好日:茶道教我的幸福15味【電影書腰版】', ISBN: '9981835423' } }, (error, response, body) =>{ console.log(JSON.parse(body)); }, ); ``` ![](https://i.imgur.com/krS9LeJ.png) ###### `postman` ![](https://i.imgur.com/CKce6rA.png) ``` js [{"id":2,"name":"當我想你時,全世界都救不了我","author":"肆一","ISBN":"5549173495"},{"id":3,"name":"我殺的人與殺我的人","author":"東山彰良","ISBN":"9262228645"},{"id":7,"name":"你已走遠,我還在練習道別","author":"渺渺","ISBN":"3722233689"},{"id":9,"name":"你是我最熟悉的陌生人","author":"Middle","ISBN":"9765734253"},{"id":22,"name":"我輩中人:寫給中年人的情書","author":"張曼娟","ISBN":"7241428897"},{"id":38,"name":"我和我追逐的垃圾車","author":"謝子凡","ISBN":"7797349452"},{"id":57,"name":"我的櫻花戀人","author":"宇山佳佑","ISBN":"2947749939"},{"id":60,"name":"你走慢了我的時間","author":"張西","ISBN":"8811544334"},{"id":66,"name":"我是許涼涼","author":"李維菁","ISBN":"8389193464"},{"id":72,"name":"日日好日:茶道教我的幸福15味【電影書腰版】","author":"森下典子","ISBN":"9981835427"},{"id":90,"name":"文學的40堂公開課:從神話到當代暢銷書,文學如何影響我們、帶領我們理解這個世界","author":"約翰.薩德蘭","ISBN":"7978376866"},{"id":95,"name":"我想吃掉你的胰臟【電影珍藏版】","author":"住野夜","ISBN":"2615985356"},{"id":100,"name":"慢情書:我們會在更好的地方相遇嗎?","author":"林達陽","ISBN":"7418527246"}] ``` ###### `作者的名字是四個字,key 錯的 ISBN 最後一碼為 7` `id:79` 這本書符合我們要找的資訊 ``` js {"id":72,"name":"日日好日:茶道教我的幸福15味【電影書腰版】","author":"森下典子","ISBN":"9981835427"} ``` ###### `PATCH方法修改書籍的 ISBN 資訊 (一樣須帶驗證)` ![](https://i.imgur.com/oI1tbPx.png) ###### `第九關` >[API文件](https://gist.github.com/aszx87410/1e5e5105c1c35197f55c485a88b0328a) ![](https://i.imgur.com/uxRt3c8.png) 想要存取的話要符合兩個條件: 1. 帶上一個 ==`X-Library-Number` 的 `header`,我們圖書館的編號是 20== 2. 伺服器會用 `user agent` 檢查==是否是從 `IE6 `送出的 `Request`==,不是的話會擋掉 ###### `偽造IE6的 request header` >[參考資料](http://www.rhdgroup.com.tw/asp/WebStat/FMozilla.asp) 訪問者HTTP_USER_AGENT字符串分析 >[參考資料](https://progressbar.tw/posts/234) 淺談網路訪問的識別證UserAgent ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); request.get( { url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info', headers: { 'Authorization': `Basic ${base64Str}`, 'X-Library-Number': 20, 'User-Agent': 'Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)', }}, (error, response, body) =>{ console.log(JSON.parse(body)); }, ); ``` ![](https://i.imgur.com/SGG8tlf.png) ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); request.get( { url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info', url:'https://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}&version=1A4938Jl7', headers: { 'Authorization': `Basic ${base64Str}`, 'X-Library-Number': 20, 'User-Agent': 'Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)', }}, (error, response, body) =>{ console.log(body); }, ); ``` ![](https://i.imgur.com/EXMOy3P.png) ###### `postman` ![](https://i.imgur.com/YExpcvP.png) ###### `query string 回傳剛剛得到的 version資訊` ![](https://i.imgur.com/J4007jL.png) ###### `第十關` 出題者會==出一個四位數不重複的數字==,例如說 `9487`。 如果猜 `9876`,`lib`會說 `1A2B`,`1A` 代表 `9` 位置對數字也對,`2B` 代表 `8` 跟 `7` 你猜對了但位置錯了。 把要猜的數字放在 `query string` 用 `num` 當作 `key` 傳給 `lib` ```javascript= const request = require('request'); let account = 'admin'; let pwd = 'admin123'; let base64Str = Buffer.from(`${account}:${pwd}`).toString('base64'); request.get( { url:'https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}&num=9613', headers: { 'Authorization': `Basic ${base64Str}` } }, (error, response, body) =>{ console.log(body); }, ); ``` ![](https://i.imgur.com/9uohEP7.png) ###### `postman` ![](https://i.imgur.com/VPFVb3K.png) ###### `第十一關` 跟菲律賓的圖書館館員打招呼 >[API文件](https://gist.github.com/aszx87410/0b0d3cabf32c4e44084fadf5180d0cf4) `Base URL`: `https://lidemy-http-challenge.herokuapp.com/api/v3` >hint: 伺服器會檢查 origin 這個 header,只要騙過伺服器就行了 >request header 內==偽造 origin== > [color=#ff9a76][參考資料](https://yakimhsu.com/project/project_w8_Ajax_Form.html) 用 ==node.js 呼叫 API== 與在==網頁上呼叫==的根本差異是什麼? ``` js Request 從瀏覽器發出來:有許多限制 自己發 Request:沒有限制 ``` >[參考資料](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/CORS) mozilla ```javascript= const request = require('request'); request.get( { url:'https://lidemy-http-challenge.herokuapp.com/api/v3/hello', headers: { 'origin': 'lidemy.com', } }, (error, response, body) =>{ console.log(body); }, ); ``` ![](https://i.imgur.com/wyD7LKR.png) ###### `postman` ![](https://i.imgur.com/c3d2Q5H.png) ###### `第十二關` >server side redirect 的原理 >轉址背後的原理 >[參考資料](https://seo.whoops.com.tw/301-302-redirect-seo/) 3分鐘了解 301 與 302 Redirect 重定向之間的差異與它們如何影響網站 SEO 排名 使用 `chrome 開發者工具`,在 `Network 分頁`中觀察 `request` ,==`網址列中輸入以下網址,訪問 API`== ``` js https://lidemy-http-challenge.herokuapp.com/api/v3/deliver_token ``` 被轉址到其他地方了 ##### `deliver_token > stopover > deliver_token_result` ==`透過 Network 分頁觀察 stopover`== ,發現 `header` 內夾帶 `X-Lv13-Token: {qspyz}` ![](https://i.imgur.com/8vS8JBT.png) ###### `第十三關` >[hint](https://lidemy-http-challenge.herokuapp.com/lv13?token={qspyz}&hint=13) 找關鍵字 代理伺服器 proxy >[菲律賓 proxy](http://free-proxy.cz/zh/proxylist/country/PH/http/ping/all) ![](https://i.imgur.com/lpwZyBA.png) ![](https://i.imgur.com/SPwTMF9.png) ###### `第十四關` >[hint](https://lidemy-http-challenge.herokuapp.com/lv14?token={SEOisHard}&hint=1) >[參考資料](https://ithelp.ithome.com.tw/articles/10209356) User-Agent 說明與使用 >[API文件](https://gist.github.com/aszx87410/0b0d3cabf32c4e44084fadf5180d0cf4) >各個搜尋引擎的[User-Agent](http://www.lrxin.com/archives-325.html) >`User-Agent` 可以設定要使用哪種搜尋引擎 ```javascript= const request = require('request'); request.get( { // 獲取首頁內容 url:'https://lidemy-http-challenge.herokuapp.com/api/v3/index', headers: { 'origin': 'lidemy.com', 'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', } }, (error, response, body) =>{ console.log(body); }, ); ``` ![](https://i.imgur.com/NkF7WZA.png) ![](https://i.imgur.com/CFT6MV5.png) --- ### 資料格式 `XML` & `JSON` ### `XML` >以前傳資料的格式,現代開發比較少用 * 全名為 Extensible Markup Language * 跟 HTML 有點像、都是標記語言 Markup Language,特色是「 ==內容用前後標籤包起來== 」,因為此格式檔案較大、且不好閱讀,所以現代開發比較少人用 XML。 ### `JSON` >比起 XML 更輕量,為現代最普遍、常用的==資料格式==。 * 全名為 JavaScript Object Notation * ==跟 JavaScript 的物件很像==,==但 key 值必須要用雙引號 "key" 包起來== ### `RESTful API` 現代 API 有一大部分都是走 ==RESTful 設計風格==。 >[參考資料](https://medium.com/%E5%8F%B2%E5%8A%AA%E6%AF%94%E7%9A%84%E7%AC%AC%E4%B8%80%E5%80%8B%E5%AE%B6/restful%E7%9A%84%E4%B8%80%E9%BB%9E%E5%BF%83%E5%BE%97%E5%B0%8F%E8%A8%98-944d0b981e82) RESTful的一點心得小記 >是一種廣泛流行的 API 設計規範、不是規定 ### 常見 Restful CRUD 指令: >[參考資料](https://blog.techbridge.cc/2019/02/01/linux-curl-command-tutorial/) Linux Curl Command 指令與基本操作入門教學 #### 取得資料: GET ``` js curl -X GET "http://www.example.com/api/resources" ``` #### 新增 JSON 資料: POST ``` js curl -X POST -H "Content-Type: application/json" -d '{"status" : false, "name" : "Jack"}' "http://www.example.com/api/resources" ``` #### 刪除資料: DELETE ``` js curl -X DELETE "http://www.example.com/api/resources/1 ``` ### 必學指令 curl >[參考資料](https://blog.techbridge.cc/2019/02/01/linux-curl-command-tutorial/) Linux Curl Command 指令與基本操作入門教學 >[參考資料](hhttps://noob.tw/postman/) API 實作(三):以 Postman 測試 API 透過 HTTP Protocol==下載和上傳檔案的指令== ``` js curl [options] [URL...] ``` #### 預設是 GET 方法 用 curl 發 request 到 google 首頁 curl 後面加網址,就會在終端機內顯示回傳的 response,可能是 HTML、JSON 或是 XML 等格式,根據輸入的 URL 內容而定。 * 最基本的作法就是: `curl http://www.google.com` #### 測試一個基本的` RESTful API` ``` js curl -X [method] [url] curl -X GET "http://localhost:3000/article/1" ```

Import from clipboard

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lost their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.


Upgrade

All
  • All
  • Team
No template found.

Create custom template


Upgrade

Delete template

Do you really want to delete this template?

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Tutorials

Book Mode Tutorial

Slide Mode Tutorial

YAML Metadata

Contacts

Facebook

Twitter

Discord

Feedback

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions

Versions and GitHub Sync

Sign in to link this note to GitHub Learn more
This note is not linked with GitHub Learn more
 
Add badge Pull Push GitHub Link Settings
Upgrade now

Version named by    

More Less
  • Edit
  • Delete

Note content is identical to the latest version.
Compare with
    Choose a version
    No search result
    Version not found

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub

      Please sign in to GitHub and install the HackMD app on your GitHub repo. Learn more

       Sign in to GitHub

      HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Available push count

      Upgrade

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Upgrade

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully