# 網路基礎概論 & 瀏覽器資料儲存
###### tags: `Network`
## 理解網路以前,先來理解溝通是怎麼一回事?
網路是如何運作的?
網站背後就是伺服器, 發個request到伺服器, 伺服器經過處理把response回傳出來, 再透過browser顯示出來.
### 傳紙條的故事 :100:
* 傳紙條的守則:
1. 寫明「來源」
2. 寫明「目的地」
3. 經過「安安您好」「哈囉我在」「太好了妳在」的前置作業確保雙方都能收到~
---
1. 標準化內容格式:例如數字統一用數字符號表示。
2. 分成 header 與 body (上與下的概念)
3. 用狀態碼標準化結果 (200/404...等表示成功/出問題等)
4. 用動詞標準化動作(get/post...)
5. 標準化的好處:轉學生一來,馬上可以進入狀況
# 關於「協定」(protocol)
## 1. 什麼是「協定」(protocol)?
網路上一種可以共通交流的模式,雙方需要依照此規則進行溝通。
## 2. 為什麼我們需要「協定」(protocol)?
為了讓彼此能夠溝通順利,減少交流成本,所以需要將規矩標準化,例如阿拉伯數字的寫法。
## 由上往下的 HTTP 協定開始講起
**What's HTTP?**
HyperText Transfer Protocol
為全球通訊網的資訊通訊基石。就像是若要透過網路傳達訊息,必須符合網路的遊戲規則(=一種協定)。而 HTTP 則像是一本遊戲規則說明書~
## 令人討厭的 HTTP request 一生
比起標題,我覺得更適合叫做 HTTP request 極其無聊的一生,因為根本就是一個小跑腿的流程~(頌芝,奉茶!)
> 雜魚 -> 傳紙條 -> 傳給千千
> 千千收到後 -> 處理紙條 -> 傳給雜魚
> 瀏覽器 -> 製造 request -> 傳給 server
> server 收到後 -> 處理訊息(紙條)-> 傳 response 回來
Server => 程式,專門處理request和response 的程式(千千)
## 我只是個計程車司機 DNS Server
Domain Name System
一個你說地標不用說地址就可以送到的概念。
比如:
:「司機大哥,麻煩送我到小巨蛋,謝謝」
:「OK,沒問題!」
以上情境司機大哥不需你跟他報地址,他也知道怎麼去~
但萬一遇到比較普龍供的司機大哥,他還是需要 google map 一下(DNS Server),查詢正確定址,這時出現的「喔~原來是台灣台北市松山區南京東路四段2號呀~」即等於網路上的 IP 位置。
2. 127.0.0.1 永遠是自己 local 端的位置。
## header and body (非網頁的)
request and response 都有 header and body。
header 放些額外資訊,body 放些主要資訊。
由上往下傳送,再由下往上解析

## HTTP Request Methods
最常見的有 get 和 post。
* `get`:拿資料 (就像是向千千訂購NBA資訊的服務,不需內容只提需求,千千回傳資料給你)
* `post`:傳送資料到伺服器/新增(真的有要訂東西,例如要訂便當囉,要回說誰要訂,我要訂幾個便當,然後還要依照特定的格式寫內容)
再來是:
* `delete` : 如名字刪除用 (跟千千說不要買了!嗯...是個奧客~)
* `put` : 把整個資料都換新
* `patch`: 更改部分資料
* `options`: 看伺服器支援哪些 method (查看店家有哪幾種包款可賣)
* `head`: 跟 get相似,差別在於 head 的 response 沒有 body。
```javascript=
原本便當:
雞腿飯 3
排骨飯 5
======
PUT
雞腿飯 2
======
便當改為
雞腿飯 2
```
```javascript=
原本便當:
雞腿飯 3
排骨飯 5
======
PATCH
雞腿飯 2
======
便當改為
雞腿飯 2
排骨飯 5
```
而get 和 post的差別寫於題四。
GET 跟 POST 有哪些區別,可以試著舉幾個例子嗎?
寫法格式:
```javascript=
<form method='GET or POST' action=''>
// 內容物
</form>
```
### get
從伺服器端拿資料,要求資料。
透過 URL 將參數送到伺服器那邊,因為是加載於 URL 後,所以參數長度會根據瀏覽器不同而有所限制。
get是把資料放在`<header>`內進行傳送,所以可以在網址列上看見資訊,並且會被記儲存於歷史紀錄中,故不適合傳送重要資料,例如密碼。
### post
從客戶端送資料過去伺服器
post是透過 HTTP 發送,就是把資料放在訊息主體(message body)內傳送,而 post的請求不會被存放到歷史紀錄中,也不會出現於網址上,並且對於資料的長度沒有限制,所以相較於get,post的請求更安全、更適合傳遞隱密性高的資料,如:密碼、登入帳號等。
查資料時看到一種比喻方式,覺得滿好理解的,就借花獻佛一下唄!
我們可以把 get 想成是明信片。所有的內容都可以被郵局人員看見,所以私密心事(如:密碼)最好不要寫在上面,以免被看光光。再者,明信片因為書寫空間不夠大,所以可寫的內容長度被限制。
而 post 就是被信封套和信件,內容無限幅度,看你想寫幾張就幾張(message body),要寫多張、要貼照片都可(資訊種類無限制)!重點是因為有資訊內容可以放在信封套裡面,所以相較明信片,更具隱密性,雖然硬打開還是看得到內容啦。
## HTTP Response Status Codes
以下為常見的 status codes:
* 200 OK
* 301 Moved Permanently(永久轉址)
```javascript=
Get a.com
status code: 301
Location: b.com
// 下次用瀏覽器去 a.com ,瀏覽器不會再對 a.com 發送 request,而是直接帶去 b.com (因為知道永久移址)
// 生活化的例子: 你想要去一家餐廳,餐廳外面已經寫著搬遷.下一次你會直接去新地址.
```
* 302 Found(暫時轉址)
```javascript=
Get a.com
status code: 302
Location: b.com
// 瀏覽器則是還會再問一次是否要去 b.com
// 生活化的例子: 你想要去一家餐廳,餐廳外面寫著修水管,會搬到隔壁.下一次你不一定會去新地址,你會先去舊地址看是否店還在.
```
400 Bad Request(client 端有錯誤): 字太醜的例子,千千看不懂~
403 Forbidden(client 端沒有權限)
404 Not Found (找不到)
500 Internal Server Error (伺服器出了問題)
503 Service Unavailable(常出現在搶票頁面)
代碼意義:
```javascript=
1xx - 等待 (Hold on)
2xx - 成功 (here you go)
3xx - 轉址 (Go away)
4xx - client 端有錯誤 (You fucked up)
5xx - server 端有錯誤(I fucked up)
```
## 由下到上的 TCP/IP 開始談起
### TCP/IP 是啥毀?
* 網路的層級,分很多層~
* 分為:
1. OSI 模型:共有七層,每層都有不同功能
2. TCP/IP 模型:僅有四層而已。為目前主要在使用的,等於簡化版的 OSI 模型。

### What's IP?
等於 Internet Protocol (網路協議地址)
既然有地址,則表示它是為了讓網路可透過「IP 協定」來識別每一台電腦(類似家裏門牌號)。
* 目前有兩種版本:
1. IPv6 是新版
2. IPv4
其中主要差異:IP 地址不同且IPv6的出現是為了解決IPv4的位置枯竭
### 各種 IP:虛擬、浮動、固定 IP
* 前提要緊:
理想狀況是希望每台電腦都有自己的 IP 可以連線(一個人一個位置)
* 斯斯有三種,IP 也是三種。哪三種?
1. 固定 IP
2. 浮動 IP
3. 虛擬 IP

上圖分為網內、網外。
* 網內的三台電腦有自己的「虛擬IP」位置(內網IP)
* 只有家裡內共用的人可以互相連接彼此的 IP 位置
* 在不同的網路裡面 IP 可以重複,因為我們彼此網路不同
* 當對網外時通常有個固定或是浮動的 IP 可以對應。
怎麼知道自己的對外 IP?
Google MyIP
其他實例
公司對外有個一個固定的 IP,但在內的每個人員工都是不一樣的 IP。網咖也是一樣的概念。
### Port 的作用
what's port?
= 連接埠,對岸人士稱為端口。他的目的很簡單,就是為了區別同一台電腦上的各種不同服務。一個 port 對應到一個服務。
* 常用的 Port
```
1. HTTP 80
2. HTTPS 443
3. FTP 21
```
### TCP 與 UDP
(在傳輸層)
* 大部分網路都建立在 TCP,因為它比較可靠,速度慢,資料保證能傳輸的到.
ex: email, web browsing
* UDP 則是比較快,但不保證一定送到。
ex: 網路電話, 音樂串流
### 淺談 TCP 三次握手
同小明小美三次對話 = 三方交握(Three-way handshake)

簡單來講:
第一次:測試 A 是否能發送,B 是否收得到
第二次:確認 A 能發送,B 能收到,測試 A 是否能收到,B 是否能發送
第三次:確認 A 能收到,B 能發送
UDP沒有這個機制,就只會一直發送而已
***
總結
記住以下表格(由下而上):
| 層級 | 層級名稱 | 名字 | 內容|
| --- | -------- | -------- | -------- |
| L5 | 應用層 | HTTP/FTP | 紙條上的內容:買便當 |
| L4 | 傳輸層 | TCP/UDP | 傳紙條時的三次確認;一直傳下去不管對方有沒有收到 |
| L3 | 網際網路層 | IP | 寄紙條,寫寄件人和收件人
| L1 | 實體層 | 海底電纜 | 郵差幫忙送信 |
> 延伸閱讀
[[網際網路] TCP/IP 階層模型基礎](https://pjchender.github.io/2018/05/26/%E7%B6%B2%E9%9A%9B%E7%B6%B2%E8%B7%AF-tcp-ip-%E9%9A%8E%E5%B1%A4%E6%A8%A1%E5%9E%8B%E5%9F%BA%E7%A4%8E/)
## 資料格式的選擇
無論是發送或接收資料,都有固定的格式。
### request Liberary
1. 一般狀況
```javascript=
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
```
2. [傳入 Authorization 的 Header](https://en.wikipedia.org/wiki/Basic_access_authentication)
底下以delete的狀況做範例
```javascript=
// const base64 = `Basic YWRtaW46YWRtaW4xMjM=`;
request.delete(
{
url: `https://lidemy-http-challenge.herokuapp.com/api/v2/books/${process.argv[2]}`,
headers: {
'Authorization': base64,
},
},
(_error, response, body) => {
console.log(response.statusCode);
console.log(body);
});
```
```javascript=
//第八關,當form和headers都存在時
request.patch(
{
url: `https://lidemy-http-challenge.herokuapp.com/api/v2/books/${process.argv[2]}`,
form:{
ISBN:process.argv[3],
},
headers: {
'Authorization': base64,
},
},
(_error, response, body) => {
console.log(response.statusCode);
console.log(body);
});
```
第九關,一點小心得!
1. 帶上一個 X-Library-Number 的 header,我們圖書館的編號是 20
=> 我是用[request Github](https://github.com/request/request)這份文件找到的,回傳statusCode是200,只剩下invalid browser,這時我想應該是寫對了

2. 伺服器會用 user agent 檢查是否是從 IE6 送出的 Request,不是的話會擋掉
=> 本來想說應該解不出來,所以我就先下了各種關鍵字,什麼IE6 Request api 之類的,但都沒找到或是可以用的看了hint了解到關鍵字其實是<mark>user agent</mark>,所以二話不說往這方面查
先找到了[第一份文件](http://tech-marsw.logdown.com/blog/2016/01/10/02-post-crawler)
雖然他是用python爬蟲,但是我看到了我要的key:'User-Agent'
接下來就是value了,先找到了[『透過用戶代理偵測瀏覽器』](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Browser_detection_using_the_user_agent)
裡面提到的這一段,好巧不巧又喵到'User Agent String'
這個關鍵字,就在這一份文件中找到了
所以就把這題解掉了!
```javascript=
request(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info',
// form:{
// ISBN:process.argv[3],
// },
headers: {
'Authorization':base64,
'X-Library-Number':'20',
'User-Agent':'MSIE 6.0'
},
},
(_error, response, body) => {
console.log(response.statusCode);
console.log(body);
});
```
//[第10關](https://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA})
## 存文字+自定義格式
* 存文字
好處:可以定義各種你想要的格式
壞處:要自己去寫出來判斷
但,通常我們會使用熱門格式:XML and JSON!
## What's XML?
Extensible Markup Language, 標記語言。利用標籤來表示屬性。
格式:
<?xml version="1.0" encoding="UTF-8"?>
```
<user>
<id>2</id>
<firstName>Joanne</firstName>
<lastName>Chu</lastName>
<avatar>https://...</avatar>
</user>
```
不過記憶體容量大,因為超多標籤,所以近年來比較常用的資料格式是超級火紅的 JSON。
## What's JSON?
JaveScript Object Notation,也是一種資料格式。他基於JS 的物件產生的格式,故與 JS 的相容性超好。
格式:
請移駕去看寫得超棒的[你不可不知的 JSON 基本介紹](https://blog.wu-boy.com/2011/04/%E4%BD%A0%E4%B8%8D%E5%8F%AF%E4%B8%8D%E7%9F%A5%E7%9A%84-json-%E5%9F%BA%E6%9C%AC%E4%BB%8B%E7%B4%B9/)
任何一種資料格式,都可以在各種語言內使用。以目前來說 JSON 為最熱門的資料格式。
**注意**
他不是物件,在key和value都要用雙刮號包住
```
var obj = {
name:'huli',
job: 'none'
}
//字串化
JSON.stringify(obj)= {
"name":"huli",
"job: "none"
}
```
其實直接看別人寫的比較快..
就我以前的印象,從server回傳給browser的資料都是<mark>JSON格式的字串(response)</mark>
如果要可以從中找到可以用的資訊,要記得轉換成物件格式(JSON.parse())
如底下的範例:
如何將 JSON 字串傳入 JavaScript 變數

```javascript=
var cart = JSON.parse ( jsonString );
alert ( cart.shopperEmail );// johnsmith@example.com
alert ( cart.contents[1].productName );//WonderWidget
```
# 除了 Web API 外,還有其他種透過網路交換資料的方式
## 第一種: SOAP
Simple Object Access Protocol
資料交換都透過 XML。
## 第二種:除了 SOAP 以外的 HTTP API
透過 HTTP 基本的 method 跟 JSON 的 response 在溝通。事實上,大多數的 API 都是長這樣子~
## 第 n 種方式:跳脫 HTTP 的限制
其實你可以自己制定交換資料的格式~
### RESTful 洗蝦?
非一種協定,只是一種推薦使用的風格~

## 各種好用工具及指令
1. curl
基本上我已經在cml上都安裝好了,只要用就可以了,他這套是在node.js的環境底下進行
老師有提供post的方法. 用這個指令就不用在輸入github的簡易request資料
```
curl --header "Content-Type: application/json" \
--request POST \
--data '{"username":"xyz","password":"xyz"}' \
http://localhost:3000/api/login
```
1. 可以在 iTerm 裡面查某個網址的 ip 位置。
```javascript=
//iTerm
打 nslookup github.com
//出現
Server: 91.187.200.206
Address: 91.187.200.206#53
Non-authoritative answer:
Name: github.com
Address: 140.82.118.4
Name: github.com
Address: 140.82.118.3
```
3. ping
測試是否有連接成功?
4. telnet
檢測 port 是否有開?
PTT 是基於 telnet 的協定。
##總結
網路主要的本質就是「溝通」!
那要能夠好好溝通的話,需要一個能夠將東西規模化,規模化之前需要先標準化,把溝通的標準制定好~
## 網頁資料都存在哪?
> 存在瀏覽器裡面,顯而易見的例子是在A電腦加入到購物車的商品,在b電腦
開啟同樣頁面,購物車的東西就清空了
## cookie
> 小型文字檔,會自動帶到server
可以用javascript把資料寫到cookie
> 比較像是伺服器和瀏覽器兩方的溝通
cookie也可以被用來當作身份驗證使用
第一次:
A -> 登入 -> server
第二次
A with 通行證-> server
這個通行證就存在cookie裡面,所以我每一次發一個request,browser都會幫我把cookie附上去
> 維基百科:
指某些網站為了辨別用戶身分而儲存在用戶端(Client Side)上的資料(通常經過加密)
> 補充:
不同domain(網址)會存不同的cookie,沒辦法拿到別的domain所存的cookie.
1. 查看存了什麼cookie的方法
Application -> cookie
2. 查看request使用了什麼cookie
Network -> 通常是最上面那一個欄位 -> Request Headers
## LocalStorage
我只想要單純透過瀏覽器和client做互動
```htmlmixed=
<div class="app">
<input class="text" /><button>儲存</button>
</div>
```
```javascript=
//在從local storage裡面拿出這個值
//getItem是去拿key喔
const oldValue = localStorage.getItem('text')
document.querySelector('.text').value = oldValue
//用setItem存進去的value只能是字串,但其實用字串就可以存很多了
// 例如: 我要存物件,透過stringify就可以轉化為字串儲存,拿出來再用json.parse拿出來
document.querySelector('button').addEventListener('click',function(){
const value = document.querySelector('.text').value
localStorage.setItem('text' , value)
})
```
## Session Storage
和LocalStorage的用法一樣,把它改成session就對了
不同分頁無法共享同一個LocalStorage.
代表一段時間儲存,如果沒有想要長期儲存的資訊就可以用這個methods存起來
## 架站/伺服器
其實伺服器就是一台電腦,只是有裝伺服器的程式
- 虛擬空間(只有空間而已,沒有操控權)
底層是一個主機,但是沒有操控權, 你不能裝一個server, 也不能用
那台電腦玩遊戲.
- 虛擬主機(一台實體主機上面有很多虛擬主機,可以視為 cloud)
最重要的一種, 像是virtual box, mac上可以跑window, 用起來和
實體主機差不多. 但是裝上去會和實體主機分享資源.
優點:遷移性比較高, 可以把程式架在別台虛擬主機上面.
管理:SSH (secure shell)
`auto scaling` 當流量大的時候,可以幫忙加開主機
- 實體主機(自己有一台完整的主機)
中華電信租一台主機, 但是伺服器壞掉,你的網站也會壞掉
## 伺服器的網路架構
server不只一台時,背後的架構

負載均衡(Load Balancer)
永遠後面有一個備份存在,不能保證有單點的東西.

## Cache: (Server和瀏覽器的機制)
重新整理的方式不同,瀏覽器運用cache的方式也不同.
放在瀏覽器到期之前,下一次就不會發request出去,而是直接從cache裡面拿
不是瀏覽器發request,就沒有cache.
需要有cache的原因很簡單, 就是不要一直發request去database拿資料
而資料是放在瀏覽器裡面.
實作: (絕對時間)
- 在response header裡面加上`Expires`, 並設定一個期限這樣資料就
實作: (相對時間,解決server端時間和client端時間不一致)
- cache control:max-age= 30.
[延伸閱讀-techBridge](https://www.youtube.com/watch?v=9hZ3JoprEAI)
### 過期了,然後呢?
過期了,不是就不能用了,如果檔案沒有變,那不就是還能用了?
在 Response 裡面 Server 會帶上這個檔案的 Etag,等快取過期之後,瀏覽器就可以拿這個 Etag 去問說檔案是不是有被更動過。
> 當快取過期之後,可以用在request 的header加上 If-Modified-Since或是If-None-Match詢問 Server 有沒有新的資源,如果有的話就回傳新的,沒有的話就回傳 Status code 304,代表快取裡面的資源還能繼續沿用。