---
# System prepended metadata

title: 網路基礎概論 & 瀏覽器資料儲存
tags: [Network]

---

# 網路基礎概論 & 瀏覽器資料儲存

###### 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
一個你說地標不用說地址就可以送到的概念。

比如：

：「司機大哥，麻煩送我到小巨蛋，謝謝」
：「ＯＫ，沒問題！」

以上情境司機大哥不需你跟他報地址，他也知道怎麼去～

但萬一遇到比較普龍供的司機大哥，他還是需要 google map 一下（DNS Server），查詢正確定址，這時出現的「喔～原來是台灣台北市松山區南京東路四段2號呀～」即等於網路上的 IP 位置。

2. 127.0.0.1 永遠是自己 local 端的位置。

## header and body (非網頁的)
request and response 都有 header and body。
header 放些額外資訊，body 放些主要資訊。

由上往下傳送,再由下往上解析

![](https://i.imgur.com/3dMEOSo.png)


## 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 模型。

![](https://i.imgur.com/SKTqik7.png)


### What's IP？
等於 Internet Protocol （網路協議地址）
既然有地址，則表示它是為了讓網路可透過「IP 協定」來識別每一台電腦（類似家裏門牌號）。

* 目前有兩種版本：

1. IPv6 是新版
2. IPv4
其中主要差異：IP 地址不同且IPv6的出現是為了解決IPv4的位置枯竭

### 各種 IP：虛擬、浮動、固定 IP
* 前提要緊：
理想狀況是希望每台電腦都有自己的 IP 可以連線（一個人一個位置）

* 斯斯有三種，IP 也是三種。哪三種？

1. 固定 IP
2. 浮動 IP
3. 虛擬 IP
![](https://i.imgur.com/eo87Fl1.png)

上圖分為網內、網外。

* 網內的三台電腦有自己的「虛擬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）

![](https://i.imgur.com/WOUEqCq.png)

簡單來講:
第一次：測試 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,這時我想應該是寫對了
![其中的這個範例](https://i.imgur.com/hYBx915.png)

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)
裡面提到的這一段![](https://i.imgur.com/oo0Evab.png),好巧不巧又喵到'User Agent String'
這個關鍵字,就在這一份文件中找到了![](https://i.imgur.com/z9TYPeE.png)
所以就把這題解掉了！

```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 變數

![](https://i.imgur.com/PbulMUM.png)



```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 洗蝦？
非一種協定，只是一種推薦使用的風格～

![](https://i.imgur.com/eh5mIz1.png)


## 各種好用工具及指令

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不只一台時,背後的架構
![](https://i.imgur.com/CT7kTQO.png)

負載均衡(Load Balancer)
永遠後面有一個備份存在,不能保證有單點的東西. 
![](https://i.imgur.com/cK4ZDyR.png)


## 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，代表快取裡面的資源還能繼續沿用。







