---
# System prepended metadata

title: 第三次
tags: [課程]

---

# 第三次
###### tags: `課程`

:::spoiler TODOs
## TODOs
- [x] intro
- [x] network layer
- [ ] TCP/IP
  - [x] port
  - [ ] ipv4, ipv6
- [x] DNS
- [ ] http
  - [x] url, query variable
  - [x] header, body
  - [x] cookies & session
  - [x] http method
  - [x] http status code
  - [x] RESTful API  
  - [ ] https
:::

:::info
開頭的廢話：
圖片基本上都是偷來的
內容也參差不齊，就加減看看ㄅ
:::

## 開頭

當你打開瀏覽器，輸入某個網址，然後就得到了某個“頁面”。在這之中到底發生的什麼事。接下來就讓我們花點時間簡單的暸解一下ㄅ。

首先有兩台電腦， Client 與 Host，也就是使用者的電腦與目標伺服器。
首先 user 輸入 `URL` 或按下某個超連結， Browser 會先去尋找 `Doemain name` 對應的 `IP address`。找到後便會製造出一個對應的 `HTTP` 資料遞給 OS，OS再將其包成`TCP/IP`封包（`data packet`）透過網卡送出。
被送出的封包會經過一堆驛站，每個驛站都會為此封包指路，最後來到 Host 端。在 Host 端所有事情會被反向的進行一遍，OS 拆開 `TCP/IP` 封包，拿出 `HTTP` 資料給 `web server` 或 `application server`，這些服務再根據 `HTTP` 內部的內容做出相對應的行為，像是給出對應的 `HTML`。
在 Host 回覆時，便會將 `HTML` 等東西包裝成一份 `HTTP` 資料，交給 OS..... bla bla bla

如果我們簡化一下流程就會是：
Client(Browser) -> `HTTP` -> Client OS -> `TCP/IP` -> Router -> `TCP/IP` -> Host OS -> `HTTP` -> Host(`web server`)

由 Client 送出的請求我們稱為 `Request`
由 Host 送出的回應我們稱為 `Response`

如果忽略中間的過程，我們可以簡化成
Client -> request -> Host
Client <- response <- Host

```javascript=
router.route('url')
    .get((req, res)=> {
        // Express 這裡的 req 指的就是來自 Client 發出的 http 資料
        // res 指的是自己將要送出的 http 資料
    })
```

至於如何包裝一份 `HTTP` 資料，以及如何與 OS 溝通，這些問題 `Node.js` 都幫我們完成了，我們只要專注於如何處理/回應傳進來的 requests 就行了。 

:::warning
注意1：
上面的講解十分片面且隨便，只能作為概念了解。
跟實際上的運作有所差異。
:::
:::warning
注意2：
在這裡講的“網頁”相關的協定在其他的網路應用上，所用的協定會有所差異。
譬如影音串流等
:::
> [延伸閱讀：從按下 enter 到看到頁面的完整詳細流程（超級fxcking詳細)](https://github.com/alex/what-happens-when#check-hsts-list)

## Network layers
> 隨便水過去，因為我也不會

![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/IP_stack_connections.svg/800px-IP_stack_connections.svg.png =x500)

> 這張圖簡單的表達了封包運送的過程

一開始的網路開發者一切都自幹，而後為了讓工作能夠分工，重複的工作可以分享，讓工程師可以專注在上層的開發... 便發明了幾套將網路流程分層的方式。

當網路資料傳送時，其中一邊的電腦一層層將資料包起來，另一邊則是將資料一層一層的分析/拆開。每一層都只會看到（也只需要）看到自己那一層負責的相關資料。
網路分層越往下越接近硬體，越往上越接進應用程式。

### OSI 7 層

![OSI-TCP/IP-FiveLayer](https://miro.medium.com/max/522/0*f_JZX-PtepdZwOlN.png)

OSI 7 層，一個常見的分類方式。但在現在其實很少會分的這麼細，基本上會以「5-Layer model」與 「TCP/IP Model」為主。

:::spoiler 小傳聞
:::warning
##### 關於 OSI 7 小傳聞 
- 據說當初發明的 OSI 7 層的人在酒吧喝的爛醉，然後有人提到或許白雪公主與七個小矮人的七跟網路很搭歐，然後他們就訂出 7 層的架構了
:::

[OSI 7 的真歷史](https://www.cs.purdue.edu/homes/comer/essay.network.layers.html)
[白雪公主與七個小矮人](https://www.explainxkcd.com/wiki/index.php/1417:_Seven)
[5-LAYER NETWORK MODEL](https://medium.com/@karthikayanmailsamy/5-layer-network-model-made-simplified-e813da0913ba)

### TCP/IP
> [wiki](https://zh.wikipedia.org/wiki/TCP/IP%E5%8D%8F%E8%AE%AE%E6%97%8F#%E5%9B%A0%E7%89%B9%E7%BD%91%E5%8D%8F%E8%AE%AE%E6%A0%88%E4%B8%AD%E7%9A%84%E5%B1%82)

#### TCP
> Transmission Control Protocol
> 隨便水過去

- TCP
  - 三相交握，SYN, SYN-ACK, ACK
  - 會先確認雙方連線正常
  - 網頁傳送通常都用這個協定
- UDP
  - 不做連線確認就發資料
  - 通常用在網路遊戲等即時性比掉包更重要的場合

#### Port

在 TCP/UDP 內容中有所謂的 "Port" 的概念。
Port 不是硬體上的，而是軟體上的實做，總共 16-bit，從 0 到 65535
Port 用作區分不同的服務，在連線時除了主機位置還需要指定 port，對於不同的 port TCP/UDP　協定會將它 forware 到不同的服務。

> 在主機名稱後 `:` 的數字就是指定使用哪個 port
> `http://some-domain-name:3000`

有些常見的系統服務會有 default 的 port譬如：
  - `22`: ssh
  - `80`: http
  - `443`: https

port 的前 1024 號都是系統用的，需要 root 權限才能使用。

```javascript=
// Express app 中的 listen function 的第一個參數就是你的服務要開在哪個 port
// 通常 3000 port 會是拿來測試的，實際上場時會使用 80 和 443 port
app.listen( 3000, '0.0.0.0');
```

> 簡單實際示範
<!-- 使用 docker nginx 開在不同 port -->

#### IP Address
> Internet Protocol
> 重點放在 IP Address
> 像是固定IP 與 virtual IP, private network
- IPv6
  - 新的協定，由於 Ipv4 的位置已經開始漸漸不夠發了因此而被推出
  - Address 由128 bits組成
  - 以每組以4位十六進制方式表示
    - e.g. `2001:0db8:86a3:08d3:1319:8a2e:0370:7344`
- IPv4
  - 舊的協定，目前大部分的設備還是採用 IPv4
  - address 由32 bits組成
  - 以每組 4 bit, 十進位表使。例如：
    - e.g. `35.194.166.209`
  - 由於 IPv4 能用的 IP 有限，因此使用 fuck my life sdfavbvjbkdfbb
	- WAN, LAN
	- class
	  - class A, B, C
	- reserved ip
		- podcast
		- localhost: 127.0.01
  - network mask
==TODO==:

## 網路設備
> 跳過
- AP
- Switch
- Router
- Bridge
- Gateway

## DNS
> Domain Name Server
> 用範例水過去，細節不重要

- 一些紀錄著 Domain name <--> IP 的對應的 server
  - 類 UNIX 系統下可以用 `whois` 與 `nslookup` 來查詢一個網域的相關資訊
  - e.g.
  - ```shell
    $whois google.com
    $nslookup google.com
    ```
- Top domain name
  - `.com`, `.edu`, `.tw`, `.io` .etc
  - example: `ncueeclass.ncu.edu.tw`
    - `.tw` 下的 `.edu` 下的 `.ncu` 下的 `.ncueeclass`
> 簡單實際示範
<!-- 操作一下 Godadyy -->

## HTTP
> Hyper Text Transport Protocol
> ==重要==

### Intro

一開始{$人名}發了一篇論文關於他發明了一套讓電腦之間傳送文本的協定，包含（URL, HTTP, HTML）
...

一開始在個人電腦流行後，Brower 也一起開始被商業運用，在“瀏覽器大戰”的時候，開始出現各種 HTML, HTTP, javascript 規格。
在最後 xxxx年，開始出統一的規格

### URL & query string/ GET parameter

使用像是檔案路徑的感覺來指定一個 Resource 的表示法
當我們想要在此 URL 上添加一些參數可以：
```
/my-blog/article?id=123
```
也可以多個
```
/my-blog/article?id=48763&name=kirito
```
這些參數被稱作 **query string** 或 **GET parameters**
> 如果你去觀察 Google search 的 URL 會發現都是在 `/search`
> 而後面的 query string 的 `q` 則是你的搜尋關鍵字

#### URL in Express
在 `Express` 中會在 `router` 裡做 URL 的匹配

在 Express 中提取 query string
[Doc](http://expressjs.com/en/api.html#req.query)
```javascript=
router.route('/my-blog/article').get((req, res)=> {
    // 當 URL 為： '/my-blog/article?id=48763'
    console.log(req.query.id);  // => 48763
    console.log(req.query.kirito);  // => undefined
});
```

另一種的提取方式（非原本的 query string 格式）
[Doc](http://expressjs.com/en/api.html#req.params)
```javascript=
router.route('/my-blog/ariticle/:id').get((req, res)=> {
    // 當 URL 為： '/my-blog/article/48763'
    console.log(req.param.id);  // => 48763
});
```
使用 param 的方式可以確定使用名稱

### Header/Body
> 由我來組成頭部！

一份 HTTP 資料可以分為 Header 與 Body 兩部份

![](https://i.imgur.com/SNJBRZy.png)
> `Response Headers` 代表 Response 的 HTTP Header

Header 裡通常放著一些設定相關的資料，像是：
```
==TODO:==
```

Body 則是放乘載著的資料，
Response Body 就會有 HTML檔之類的東西
![](https://i.imgur.com/7kn5gA8.png)

Request Body 則會有 Client 要送出的資料（像是註冊資料）
或是上傳檔案之類的
![](https://i.imgur.com/dudcSmQ.png)

#### Express Head/Body
```json=
// Body
{
  "id": "123"
}
```
```javascript=
// Node.js code
console.log(req.body.id);  // 123
```
> request Body 不一定要是 json 格式，只是因為 Node.js 與 json 相性高便拿 json 格式示範

### Cookie & Session
> 餅乾！ 講話！

在 header 中有一個特別的 key，叫做 `cookie`。 cookie 為很多對的 `key:value`
`cookie` 會由 Host 發給 Client，而Client 的 Browser 會將 `cookie` 儲存起來，在下一次對 Host 發 Request 時，這份 `cookie` 就會被加在 header 中。

> `cookie` 的用處在於辨識

假設今天我 Host 收到一個 Request 要我做一份雞排，而後 Host Response 一個 `cookie: number=c8763`。之後，如果有一個 Request 的 `cookie` 內容是 `number=c8763` 那麼我就能知道，這個 Request 是來自剛剛跟我點雞排的人。

#### Session
> 一套登入相關的機制

在 Host 端儲存一個 session table，當有使用者成功“登入”後，我們 Host 便發給此使用者一個特殊的 `cookie` 稱為 `SessionID`，內容為一串難以被猜到的亂碼。
每個 `SessionID` 會定應到到 session table 中特定的空間，這個空間裡就可以紀錄此使用者ID為何。

```javascript=
(req, res)=> {
	// 這裡的 req.session 就是 session table
	// req.session.username = 'c8763'
  
  req.session.name = req.body.username;
  req.session.雞排 = {
    切: req.body.雞排.切,
    辣: req.body.雞排.辣,
  };
}
```

#### JWT
> 反正用不到，可以不用看這一章節
> json web tokens
> 這一次 ncufresh 應該不會用到這個技術，會加上來是因為某人跟我提到這個我本來也不知道的東西

相對於傳統的 session ，另一種的登入方式。
簡單來說就是在body中加入一段加密過的 token, 裡面也包含 username 等資料
這樣一來 username 等資料便是存在 user 端而不是 host 端。
（username 資料與 Signature 的加密是"綁在一起"的，因此無法任意竄改 username，詳情請見「密碼學」）

    Header(標頭): 用來指定 hash algorithm(預設為 HMAC SHA256)
    Payload(內容): 可以放一些自己要傳遞的資料
    Signature(簽名): 為簽名檢查碼用，會有一個 serect string 來做一個字串簽署

- [官網](https://jwt.io/)
- [5*Ruby](https://5xruby.tw/posts/what-is-jwt)
- [ithome](https://ithelp.ithome.com.tw/articles/10196759)

### HTTP Methods
> 方法！

每一份 HTTP request 還會有個 **Method** 屬性，用來表達此次 request 的意圖

- GET
  - 取得資料
  - 通常**沒有Body**，額外資訊在 URL 的 query string 上（這也是為什麼 query string 也稱為 Get parameter）
- POST
  - 對此資源更新資料
  - 要更新的資料放在 Body 裡
- PUT
  - 更新“部分”資料
  - 一樣，要更新的東西放在 Body 裡
- DELETE
  - 刪除資料
- HEAD
  - 只取得 Header
- ...

HTTP Method 不是強制要遵守的！你要全部用 `GET` 或更反人類的全部用 `DELETE` 也可以。
但是為了自己與同事的頭髮著想還是遵守一下這個規範吧。

[更多細節](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Methods)

#### In Express

在 Express 的 Router 中對於同一個 URL 可以讓不同的 Method 導到不同的地方
```javascript=
router.route('/my-blog/article/:id')
    .get((req, res)=> {
        controller.getArticle(req.param.id);
    })
    .put((req, res)=> {
        controller.updateArticle(req.body, req.param.id);
    })
    .delete((req, res)=> {
        controller.deleteArticle(req.param.id);
    });
```

### Status Code
> 用來表達現在的狀態（Host 給 Client）
> 像是最常見的：404 Not Found!

 一套使用簡短的代碼來表達一個 HTTP 請求是否完成的方法
 像是：
 - 2xx 表達成功
   - `200` OK
 - 3xx 重新導向
   - `302` Found (像是登入後把你導到其他頁面)
 - 4xx Cline 端的問題
   - `404` Not Found
   - `481` I'm a teapot cannot brew coffe
 - 5xx Server 端的問題
   - `500` Internal server error
 
[詳細列表](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status)
[nyan](https://http.cat/)

#### Express
```javascript=
req.status(404).send('Page Not Found! QQ');
```

### RESTful API
> 不是一套標準，而是一種風格

將每一個 http request 視為一個 "動詞+名詞" 的指令
動詞的部分由 http Method 來提供，在需要更多自定義動詞的情況下需要自己訂一套固定的表達法，在 URL裡
名詞的部分為 URL，URL 內只應該表達一個“東西”

因此每一個請求都是對某個“物件”做某個“操作”

```
this=> GET /player?id=123
this=> GET /player/123
this=> DELETE /player/123
this=> GET /player/1/item/48763
this=> GET /player/1/item/48763/_COMSUME

not => GET /get_player/123
not => GET /del_player?id=123
```

[Mopcon 共筆--RESTful](https://hackmd.io/gUGu05hES1GMbdrny70iyQ?view#%E4%BB%80%E9%BA%BC%E6%98%AFREST)

### HTTPS
> Secure!

跟第三方認證機構認證自己的身份後
PAIN PAIN PAAAAINNNNNN
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

- ==TODO:==



## Some References
> 沒事就看看吧
- [express API doc](https://expressjs.com/en/4x/api.html)
- history
  - [http 發展歷史](https://segmentfault.com/a/1190000023312905)
  - [瀏覽器 大戰](https://www.mozilla.org/zh-TW/firefox/browsers/browser-history/)
  - [[Code Rush] --瀏覽器大戰紀錄片](https://www.youtube.com/watch?v=VoLUvE-ny1k)
- [OSI layer(ithome)](https://ithelp.ithome.com.tw/articles/10000021)
- [sitcon2019 共筆: 網路 / HTTP / RESTful 觀念及實做](https://hackmd.io/@SITCON/camp2019-the-net#)
- [Mopcon2020 共筆: 優雅的 API 設計 - 後端工程師必修的設計模式](https://hackmd.io/gUGu05hES1GMbdrny70iyQ)
- [Medium: 「筆記」- 何謂 HTTP 傳輸協定](https://medium.com/pierceshih/%E7%AD%86%E8%A8%98-%E4%BD%95%E8%AC%82-http-%E5%82%B3%E8%BC%B8%E5%8D%94%E5%AE%9A-1d9b5be3fd24)
- [鳥哥的 linux 私房蔡(詳細的網路描述)](http://linux.vbird.org/linux_server/0110network_basic.php#whatisnetwork)
- [DNS blog](https://medium.com/%E5%BE%8C%E7%AB%AF%E6%96%B0%E6%89%8B%E6%9D%91/%E5%9F%9F%E5%90%8D%E7%B3%BB%E7%B5%B1-dns-101-7c9fc6a1b8e6)
- [優質文章列](https://ithelp.ithome.com.tw/users/20116003/ironman/2935?page=2)
- 我看不懂
	- [syscall & TCP/IP](https://developer.ibm.com/technologies/systems/articles/au-tcpsystemcalls/)

