# 網路基礎概論 & 瀏覽器資料儲存 ###### 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 放些主要資訊。 由上往下傳送,再由下往上解析 ![](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,代表快取裡面的資源還能繼續沿用。