本篇為 [NET101] 網路基礎概論(搭配 JS 實作練習) 這門課程的學習筆記。如有錯誤歡迎指正。
1 | 學習目標: |
HTTP 是什麼?
全名是 HyperText Transfer Protocol,中文翻作「 超文本傳輸協定」。
HTTP 是一套網路傳輸協定,為全球資訊網的資料通訊的基礎。也就是說,網頁前端和後端在溝通時,就是透過 HTTP 協定進行。
為什麼我們需要 Protocol(協定)?
簡言之,協定就是一個「標準」。協定是為了讓彼此溝通而建立的規範,制定標準以統一格式,如此能夠進行規模化。
Client & Server
而透過協議溝通的兩端,通常可分為客戶端(Client)和伺服器端(Server)。

我們如何看到網頁的畫面?
網頁上的資訊,其實就是由許多 request 跟 response 構成。且兩者內容均分成 header 與 body,分別帶著不同資訊:
- header:額外資訊
- body:主要內容
我們可透過瀏覽器的開發者工具、或是 HTTP 抓包工具 Charles 來查看詳細資訊,過程大致如下:
- 瀏覽器(Client)產生 HTTP「request」傳給 Server
- Server 經過處理後,回傳一個「response」
- 再由瀏覽器進行解析(html、css、js 等),將程式碼渲染成我們所熟悉的網頁介面

DNS 域名系統
全名是 Domain Name System,負責將域名轉換成 IP 位置。
- 域名(Domain):即常用的網址。google.com 就是一個域名,類似景點名稱。
- IP 位置:每個主機都有個 IP 位置,是網路溝通的地址。由四個數字組成,範圍是 0 ~ 255。
補充:localhost 跟 127.0.0.1 是什麼?
localhost:是一個域名,對應的的 IP 位址是 127.0.0.1127.0.0.1是回送地址,指本地機,一般用來測試使用
以查詢地址為例
- 如果今天想要抵達 台北 101(域名)
- 查詢 Google 地址在哪(DNS)
- 回覆正確地址:台北市信義區信義路五段 7 號(IP)
Google 提供免費的 DNS 伺服器 8.8.8.8 和 8.8.4.4,如此可透過搜尋引擎來蒐集大數據。
以 GitHub 網站為例
就是透過 DNS 把 Request URL(github.com) 轉換成實際 IP 位置(13.250.177.223)。

nslookup 指令
在終端機輸入 nslookup '網址':可查詢 DNS 伺服器。有可能出現多個結果,代表對應到多個 server。

瀏覽器只是一個程式
即使我們沒有瀏覽器,也能夠過其他方式發送 request 跟取得 response。
實做一個 Client 端發送 request
利用 Node.js 的一套 library:request - Simplified HTTP client,來模擬瀏覽器發送 request 的過程,步驟如下:
- 安裝套件:
npm install request - 使用方法:複製官網提供的範本,貼到 index.js 裡
1 | const request = require('request'); |
- 修改成要發送 request 的域名
1 | const request = require('request'); |
- 執行
node index.js可拿到 response

- 或是利用
node index.js > github.html導入程式碼,一樣能打開網頁
HTTP Request Method 請求方法
什麼是 HTTP Method?在 HTTP 1.1 協定中,定義了八種方法,來以不同方式操作指定的資源。詳細可參考 HTTP 請求方法- HTTP | MDN:
- GET:只應用於取得資料
- HEAD:只獲取回應的 header,但沒有 body。較少使用,通常應用在只想知道 response 資訊時
- POST:用於提交指定資源的實體。通常會改變伺服器的狀態
- PUT:取代原本的整個 request。和 PATCH 類似
- PATCH:修改部分 request
- DELETE:刪除資源
- OPTIONS:會回傳 server 支援哪些方法
- TRACE
- CONNECT
這是為了讓 Server 能夠清楚辨別 request 的目的。
CRUD 原則
常用的幾個動作分別為:GET / POST / PUT / DELETE,正好對應到資料庫基本操作 CRUD 增刪查改:
- Create:新增(POST)
- Delete:刪除(DELETE)
- Read:讀取(GET)
- Update:更新(PUT)
RESTful
- REST:全名是 Representational State Transfer,中文為「表現層狀態轉換」,是一種設計風格,以語意化且更為嚴謹的方式描述 API
- RESTful:形容以此規範設計的 API
一般的 API 可能會長這樣:
1 | 新增使用者:POST + /new_user |
若以 RESTful API 風格開發:
1 | 新增使用者:POST + /users |
由此可見 RESTful 的寫法較一致,且語意化更好理解。透過把「動作」藏在 HTTP method 裡面,而有唯一的 URL(/users)表示資源位置,藉此統一 API 接口。
如果用 HTML 來比喻,寫網頁時我們可以全部使用 div 標籤,但為了幫助理解,通常會使用 li、section、article 等具有語意的標籤,即可從結構看出內容的作用。
參考資料:API 是什麼? RESTful API 又是什麼? - Medium
GET & POST 請求的區別
當中又以 GET 和 POST 兩種,為最常使用的 HTTP 請求方法。兩者最直觀的區別是「資料傳遞方式」與「安全性」。
GET:向指定的資源要求資料,類似於查詢操作。
- 資料傳遞方式:將引數由 URL 帶至 Server 端
- 安全性:較 POST 不安全,因為傳遞的引數會在 URL 上顯示
- 例如:讀取連結或圖片

POST:將要處理的資料提交給指定的資源,類似於更新操作。
- 資料傳遞方式:將引數放在 request body 中傳遞
- 安全性:較 GET 安全,適合用於隱密性較高的資料
- 例如:會員登入系統(如下圖所示)

在最下方夾帶 request 資訊:

HTTP Status Code 狀態碼
是 HTTP 用「3 位數字代碼」來表示回應狀態,通常以開頭的數字來進行區分。詳細可參考 HTTP 狀態碼- 維基百科:
1xx:訊息(較少見)
2xx:Success 成功
200 OK:代表成功204 No Content:伺服器成功處理了請求,沒有返回任何內容(例如發出 DELETE XXX 訊息,回傳 204 代表刪除成功)
3xx:Redirect 重新導向
301 Moved Permanently:資源「永久」移到新位置302 Found:資源「暫時」移到其他位置
4xx:User error 客戶端錯誤
400 Bad Request:請求語法錯誤、資源太大、請求訊息無效等404 Not Found:找不到資源
5xx:Server error 伺服器端錯誤
500 Internal Server Error:伺服器出錯。例如搶票時伺服器當機503 Service Unavailable:由於臨時的伺服器維護或者過載,伺服器當前無法處理請求
參考資料:
- [第四週] 網路基礎 - HTTP、Request、Response - Yakim
- [Day 09] 表單中的 GET 與 POST
- GET 和 POST 請求的區別(面試和原理都得知道)
- http Post 和 Get 差異
實作一個簡易 HTTP Server 端
前面我們已經實作一個 Client 端,也就是利用 request 這個 library 來顯示出來。接下來我們要利用 Node.js 內建 library:http 來實作 Server 端:
- 建立一個檔案
server.js,並輸入下列程式碼:
1 | let http = require("http"); // 引用 library: http |
執行
node server.js:不會跑出任何東西。因為沒有console.log任何東西,所以是正常的。此時程式會一直執行到按Crtl + C才會退出,符合 server 端必須不斷運行來接收資訊。在瀏覽器輸入網址
localhost:5000會跑出下列畫面:

- 若修改程式碼如下,即可根據「不同網址」給出「不同回應」:
1 | let http = require("http"); // 引用 library: http |
- 輸入網址
localhost:5000:回應 welcome

- 輸入網址
localhost:5000/hello:回應 hello

- 再增加
redirect部分和res.writeHead(404),就完成一個較完整的 Server 端:
1 | let http = require("http"); // 引用 library: http |
- 若輸入不存在的網址,就會出現狀態
404 Not Found:

- 若輸入
localhost:5000/redirect,會在 Response Headers 會出現'lidemy': 'good':

- 在之前的狀態碼有提到,若要轉址必須改成
302 Found:
1 | if (req.url === "/redirect") { |
- 輸入網址
'localhost:5000/redirect,瀏覽器就會轉址到新位置:

- 若將程式碼改成
'Location': 'https://google.com':輸入網址localhost:5000/redirect就會直接連到google.com
淺談 TCP/IP
網路的層級
先前提到「從電腦發出 request 到 server」,在溝通訊息這段過程,其實需要經過非常多道手續。因此就有組織將網路標準化,將網路連接過程分成數個階層(layer),每個階層都有特別的獨立的功能。
分層的好處,是只要處理該層級的事情就好,因為每個階層的程式碼可以獨立撰寫,功能也不會相互干擾。
而著名的分層模型主要有兩種:
OSI 七層協定
由於協定非常嚴謹,較偏向理論。

TCP/IP 四層模型
TCP/IP 是由 OSI 七層協定簡化而來,為目前網路通訊的基礎架構。以下為兩者之間的比較圖與常見的通訊協定:

參考資料:2.4 TCP/IP 的傳輸層相關封包與資料 - 鳥哥的 Linux 私房菜
網路層 - IP 地址
IP 的全名是 Internet Protocol,中文是「網際網路協定」。
可分為 IPv4、IPv6 這兩種協議,兩者最主要差異在於「IP 地址的不同」:
- IPv4:由四個數字組成,範圍是 0~255
- IPv6:用來取代 IPv4,主要是為了解決 IP 地址不夠用的問題,可容納更多 IP 地址
各種 IP
我們常聽到的 IP 地址,代表在網路上的地址。在網際網路上,每台電腦之間,是透過 IP 位址來通訊。當中又分為下列幾種類型:
- 固定 IP:不會改變的 IP
理想情況下,是每一台電腦都有一個 IP 位址。固定的 IP 位址,適合架設網站,也因為不會變動,確保使用者能夠連上伺服器。例如:伺服主機、網路設備多使用固定 IP。
- 浮動 IP:每次連上網路時的 IP 位置都會不一樣
一般用戶大多是浮動 IP。浮動 IP 解決了「IP 不夠用」這個問題,因為每次連線的 IP 位址皆不同,也不會輕易被駭客攻擊。
- 虛擬 IP:僅能使用於內部網路,外網連不上該位置
只有在內網才能互相連接,外網找不到該地址,所以內網 IP 位址是可以重複的。但對外網而言,一定會有一個「固定 or 浮動」的 IP 位址。例如:公司使用內網溝通,藉由鎖 IP 位址,可提高安全性。
通常以
192.168或10.0開頭的,都是虛擬 IP。

參考資料:浮動 IP 與 固定 IP 有何不同?? 各有何優缺點??
Port 連接埠(端口)
在應用層當中,每台電腦主機 IP 位置(localhost),可能對應到不同應用程式。例如:HTTP、FTP、信件收發等服務。
而 Port 扮演網路通訊的端點,用來區分不同功能。如此即可辨認出,該連線要對應到哪個應用程式。
- 例如實作 server 端提過的
server.listen(5000):代表監聽5000這個 Port,輸入網址localhost:5000即可連到這個服務
如果沒有輸入 Port,會有一些預設或常用值:
- HTTP 80:說明用於網頁瀏覽
- HTTPS 443
- FTP 21
- 「測試」常用:3000、4000、8080、8000 等冷門 Port
參考資料:[網路管理]常用 port 說明
傳輸層 - TCP & UDP
傳輸層(Transport Layer)協定提供不同主機之間的資料傳輸及控制。根據不同需求,又分為「可靠的 TCP」和「速度較快的 UDP」兩種協定:
TCP
- 全名:Transmission Control Protocol 傳輸控制協定
- 是一種可靠的資料傳輸,因此大部分的網路協定都是建立在 TCP 上面
- 透過「三次握手」確認建立一個連接:

1 | 若以「傳紙條概念」比喻三次握手: |
UDP
- 全名:User Datagram Protocol 用戶資料包協定
- 流量是不受規範的,需要快速、重複傳送資料的情況會使用 UDP,相對而言也較不穩定
- 例如:視訊功能
參考資料:
- TCP 協議 - Wikipedia
- 什麼是 OSI 的 7 層架構?和常聽到的 Layer 7 有關?
小結 - 從傳紙條概念看 TCP/IP
參考 Huli - 從傳紙條輕鬆學習基本網路概念,我們能夠透過傳紙條的例子,來試著理解網路通訊概念:
- 應用層(HTTP / FTP):傳輸的資料內容
- 傳輸層(TCP / UDP):傳輸方式
- 網路層(IP):傳輸地址
- 實體層(網路電纜):實體傳輸

淺談 API
可參考 Huli - 從拉麵店的販賣機理解什麼是 API,或是這部影片:什麼是 API?來瞭解。
全名是 Application Programming ==Interface==,中文是「應用程式==介面==」。簡言之,就是方便溝通、交換資料的管道。
API 是應用程式、裝置之間資料的交換,但不一定要透過網路才能有 API,例如:
- 軟硬體廠商的 API:USB 與 電腦交換資料
- 作業系統裡的 API:讀取、傳輸及寫入等等電腦上的操作
而對於網頁來說就是 Web API
- Web API:是基於 http 協定下運作的 API,代表透過網路進行資料交換
以下為實際的運用例子:
- 會員登入系統:社群連結註冊登入(例如:設置 FB 或 Google 登入按鈕)
- 社群嵌入:分享、留言版、按讚按鈕、影音(例如:Facebook Graphic)
- 資料嵌入:Yahoo 氣象、Google 地圖、Tweet timelines
- PokéAPI:拿到寶可夢的資訊
- 假圖 API:隨機產生出圖片
透過 API 能夠達到省時、便利、營利等優點,因此我們也可以說,API 是一個「能讓生產者與消費者雙方溝通的介面」。
實際串接 API
串接的前置作業
- 準備 Client 端(發出端):使用 node.js library request 實作一個 Client 端
- 提供 API 的網站(接收端):Regres 是一個提供 API 測試的網站
- 能夠發出 request 的工具:終端機
實戰演練
Step1. 實作一個 Client 端
與先前「實做一個 Client 端發送 request」操作方式相同,是利用 library request 來模擬瀏覽器發送 request 的過程。
- 新增 index.js 並貼上官網提供的範本:
1 | const request = require("request"); |
Step2. 串接 Regres API
將範本中的 google 網址改成 https://reqres.in/api/users
Step3. 用 node.js 運行
在終端機輸入 node index.js,即可獲得 Regres API 所提供的資訊:

這樣其實就完成了簡單的 API 串接!透過丟一個 request 到網站,我們能夠獲取想要的資訊。
學會查看官方文件
而透過 request 文件,我們能找到不同的 request.METHOD(),瞭解如何使用各種方法:
1 | request.get(): Defaults to method: "GET". |
情境一:查詢不同使用者資料
- Method:GET(預設方法)
- url :
https://reqres.in/api/users/<userID> - 透過 Reqres 官網可知,更改 「Request 網址結尾」可獲得不同使用者資訊,以
/api/users/2為例:
方法一:直接將網址改成 https://reqres.in/api/users/2

方法二:使用 node.js 內建 library process
這個方法是利用 process.argv 達成帶入參數,我們可以先用 console.log 來查看 process.argv 是什麼:
1 | const process = require("process"); |

會發現 process.argv 其實是一個陣列,利用 process.argv[2] 就可以拿到我們需要的參數:
1 | const request = require("request"); |
輸入 node index.js 2,就可獲得 id: 2 的使用者資料:

情境二:新增使用者資料
- method:POST
- url :
https://reqres.in/api/users/ - 到 request library 的 Github 頁面,點選 forms,填入相關程式碼來新增資料至 reqres
1 | const request = require("request"); |
成功新增使用者資料:
註:這裡的操作只是測試用,並不會真的新增資料到網站。

情境三:刪除使用者資料
- method:DELETE
- url :
https://reqres.in/api/users/<userID>
1 | const request = require("request"); |
回傳 204,代表成功刪除使用者資料:

情境四:修改使用者資料
- method :PATCH
- url :
https://reqres.in/api/users/<userID>
1 | const request = require("request"); |
成功修改使用者資料:

綜合應用
Base URL: https://lidemy-book-store.herokuapp.com
| 說明 | Method | path | 參數 | 範例 |
|---|---|---|---|---|
| 獲取所有書籍 | GET | /restaurants | _limit:限制回傳資料數量 | /restaurant?_limit=6 |
| 獲取單一書籍 | GET | /restaurants/:id | 無 | /restaurant/12 |
| 刪除書籍 | DELETE | /restaurants/:id | 無 | 無 |
| 新增書籍 | POST | /restaurants | name: 書籍名稱 | 無 |
| 更改書籍 | PATCH | /restaurants/:id | name: 書籍名稱 | 無 |
1 | const request = require("request"); |
補充:如何在請求帶入資料
在發出 request 時,我們其實能透過兩種方式來帶入資料:
- Request header:把資料放入 header
- 通常會放層級較高、具有機密性的資料,例如身分驗證
- Query-string parameter:把資訊放在網址列結尾
- 由結尾的問號開始,是 KEY / Value 的組合
實際例子可參考Twitch API v5 文件,同樣支援這兩種方法:
- Request header (
Client-ID: XXXXX) - Query-string parameter
(https://api.twitch.tv/kraken/users/44322889?client_id=XXXXX)
因此在串接之前,必須先確認該 API 支援哪種方式來發出請求。
資料格式 XML & JSON
在 API 實戰中的 response 資料其實就是「JSON 格式字串」。在談到如何整理資訊之前,先來介紹常用的資料格式:
XML
- 全名為 Extensible Markup Language,中文為「可延伸標記式語言」
- 和 HTML 非常類似,均屬於 Markup Language(標記語言),內容用
前後標籤包起來。- 例如:
<firstName>John</firstName>
- 例如:
- 缺點是檔案較大、不易閱讀,因此現代開發較少使用
JSON
- 全名為 JavaScript Object Notation,中文為「JavaScript 物件表示法」
- 為現代最普遍、常用的資料格式
- 格式容易理解,且相容性高,許多程式均支援讀取或修改
- 資料格式看似 JavaScript 物件,但需注意以下幾點:
- 回傳值的型態是「字串」
key值要用雙引號"key"包起來- 支援許多資料格式:
[array]、{object}等;但value 值不能放 function - 整個 JSON 格式字串不能使用註解
- 相關函式
JSON.prase(<JSON>):將 JSON 格式字串轉成物件JSON.stringify(<object>):將物件轉成 JSON 格式字串
參考資料:
- 你不可不知的 JSON 基本介紹
- JSON Editor online:可將得到的資料轉成 JSON 格式
實際來處理 JSON 格式字串
同樣以串接 Reqres API 為例。得到 response 就是「JSON 格式的字串」,但這種資料並不易閱讀,也無法直接使用。
因此使用內建函式 JSON.parse() 做處理,就會轉成「JS 物件」:
1 | const request = require("request"); |

如此就可以「物件」方式來取出想要的資料:
1 | const request = require("request"); |
反之,若想把「JS 物件」轉成「JSON 格式字串」,可以用: JSON.stringify(<object>)
必學指令 curl
在 curl 官網下載,安裝方法可參考 Day14 - cURL 工具,即可在終端機使用。
curl 做法非常簡單,只要在終端機輸入指令就可支援發 HTTP request 、下載及上傳檔案的功能,基本格式為:
1 | curl [options] [URL...] |
預設是 GET 方法
以使用 curl 能夠發 request 到 google 首頁為例:
- 輸入
crul 'http://www.google.com':即可下載該網頁程式碼 - 或輸入
crul '網址' > google.html:可將回傳值導向其他檔案

參考資料:
- linux 指令 curl 指令详解
- Linux Curl Command 指令與基本操作入門教學