# 第三次
###### 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
> 隨便水過去,因為我也不會

> 這張圖簡單的表達了封包運送的過程
一開始的網路開發者一切都自幹,而後為了讓工作能夠分工,重複的工作可以分享,讓工程師可以專注在上層的開發... 便發明了幾套將網路流程分層的方式。
當網路資料傳送時,其中一邊的電腦一層層將資料包起來,另一邊則是將資料一層一層的分析/拆開。每一層都只會看到(也只需要)看到自己那一層負責的相關資料。
網路分層越往下越接近硬體,越往上越接進應用程式。
### OSI 7 層

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 兩部份

> `Response Headers` 代表 Response 的 HTTP Header
Header 裡通常放著一些設定相關的資料,像是:
```
==TODO:==
```
Body 則是放乘載著的資料,
Response Body 就會有 HTML檔之類的東西

Request Body 則會有 Client 要送出的資料(像是註冊資料)
或是上傳檔案之類的

#### 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/)