# [後端概念] 負載均衡/Http Cache/CORS
###### tags: `後端`
## 負載均衡(Load Balancer)
>一個可以把接收的資料分佈給其他機器的功能。好處是,當伺服器能力不足的時候,可以輕易的添加機器,而當其中一台伺服器壞掉的時候,也不會導致服務整個掛掉。

## http cache 快取
### HTTP有哪些狀態碼?
常見的如下:
```
200 - 請求成功
301 - 資源(網頁等)被永久轉移到其它URL
404 - 請求的資源(網頁等)不存在
500 - 內部服務器錯誤
```
**第一個十進制數字定義了狀態碼的類型**,後兩個數字沒有分類的作用。HTTP狀態碼共分為5種類型:
```
1** 信息,服務器收到請求,需要請求者繼續執行操作
2** 成功,操作被成功接收並處理
3** 重定向,需要進一步的操作以完成請求
4** 客戶端錯誤,請求包含語法錯誤或無法完成請求
5** 服務器錯誤,服務器在處理請求的過程中發生了錯誤
```
### HTTP vs HTTPS
>HTTPS 全名 **超文本傳輸安全協定**,那個 **S 就是 Secure 的意思**;
>
>HTTPS在傳統的HTTP和TCP之間加了一層用於**加密解密的SSL/TLS层**
| HTTP | HTTPS |
| -------- | -------- |
| 無法驗證身份 | **非對稱加密(一把「公鑰」,一把「私鑰」)** |
| 訊息沒加密 | **對稱加密(同一個金鑰來進行加密與解密)** |
| 無法驗證訊息完整性 | 雜湊(Hash) |
### HTTPS 加密過程
https://medium.com/@Tommmmm/ssl-%E5%8A%A0%E5%AF%86%E5%8E%9F%E7%90%86-f5a80e9a589e
A: 使用者, PA: A的公鑰, SA: A的私鑰, DA: A公鑰加密後的文件
B: 商城 , PB: B的公鑰, SB: B的私鑰, DB: B公鑰加密後的文件
```
step1. (A->B) A向B丟requests,向B索取SSL憑證
step2. (B->A) B回傳SSL憑證, PB給A
step3. (A->B) A確認SSL憑證無誤後,用PB把要給B的資料加密,形成DB,並把PA、DB傳給B,PB留著
step4. (B->A) B用SB解開DB確認無誤後,用PA把要給A的資料加密,形成DA,並把DA回傳給A,PA留著
step5. A用SA解開DA確認無誤後,雙方即使用各自的公鑰(PA、PB)開始傳輸資料
```
### 為什麼需要Cache?
>省流量、省時間、減少資源的損耗
1. Server side的cache:
>網頁上某些資源不會每天變動,若使用者每次request都要去跟DB要資料,會拖垮DB的效能。因此,把DB的資料撈出來之後存到別的地方,如: Redis,需要用的時候再以極快的速度去撈出來,就可以減低DB的負擔。
2. Server跟Browser之間的Cache機制:
>概念一樣,網頁上的圖片就很適合把他們Cache起來。
`HTTP Response Header`裡面可以加的字段:
一、決定可以儲存response的快取是哪種:
1. 私有的 `private cache` ,**只能被私有快取儲存**,共用快取不行,通常用於**個人敏感資料**, ex: 瀏覽器快取
2. 公用的 `shared cache` , **可被任何共用、私有快取儲存**, ex: CDN
二、可不可以存快取:
1. `no-store` : **request和response的內容都完全不存,每次都要從server拿資源 (永遠不用快取)**
2. `no-cache` : **可以存快取**,但使用快取前**每次都要送request 問server,server沒有更新的檔案版本才可以用 (永遠檢查快取)**
三、新鮮度:
1. `Expires`: **cache到期的時間**。
2. `Cache-Control: max-age` : 指定從目前請求開始,允許擷取的回應**重複使用的最長時間 (單位為秒)**
舉例來說,`Cache-control: private, max-age=600` 表示用戶端瀏覽器最長只能快取回應使用 10 分鐘 (60 秒 x 10 分),之後就要向伺服器詢問是否有新版本。
* 若`max-age`與`Expires`同時出現,**以`max-age`優先(蓋過)。**
四、`Last-Modified` 與 `If-Modified-Since`
>在 Server 傳送 Response 的時候,可以多加一個`Last-Modified`的 Header,**表示這個檔案上一次更改是什麼時候。**
>
>而當快取過期,瀏覽器下次再發送 Request 的時候,就可以利用這個資訊,**改用`If-Modified-Since`來跟 Server 指定拿取:某個時間點以後有更改的資料。**

五、認證權杖`ETag`
**`ETag` 是一組由 server 計算的 hash** ,就像是大家常聽到的 md5 一樣,server用一套演算法函數,**根據實體檔案的一些資訊去計算出一個 hash code 來當檔案認證碼,不同的檔案丟進這個函數就會得到不同的hash code。**
用戶端在 `max-age` 過期後,向伺服器發送檔案 request 時會夾帶這 `ETag` 資訊,伺服器會計算伺服器上的該檔案 `ETag` 是否已改變,分成兩種case:
1. YES(已改變),**傳送該檔案**
2. NO(沒有改變),回傳 `status code : 304 (Not Modified) `,告訴用戶端,**沒有新版本,使用快取即可。**


* [新手坑:讓人又愛又恨的 HTTP Caching](https://medium.com/frochu/http-caching-3382037ab06f#e05b)
* [循序漸進理解 HTTP Cache 機制](https://blog.techbridge.cc/2017/06/17/cache-introduction/)
* [HTTP caching](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Caching)
## CORS(跨域資源存取)
### 何謂CORS
* **CORS(Cross-Origin Resource Sharing)跨域資源共享**
* **是一種跨域的解決方案。**
>因為**同源政策**的原因,**非同源的request會因為安全性考量而受到限制,須強制你遵守CORS的規範,否則request會失敗。**
>
>CORS 是針對不同源的請求而定的規範,**透過 JavaScript 存取非同源資源時,server 必須明確告知瀏覽器允許何種請求,只有 server 允許的請求能夠被瀏覽器實際發送,否則會失敗。**
### 怎樣才算同源?
```
1. 相同的通訊協定 (protocol),即 http/https
2. 相同的網域 (domain)
3. 相同的通訊埠 (port)
```
**Origin(同源)**
>首先,瀏覽器發送跨來源請求時,會帶一個 Origin header,**表示這個請求的來源。**
**Access-Control-Allow-Origin**
>當 server 端收到這個跨來源請求時,它可以依據「請求的來源」,亦即 Origin 的值,決定是否要允許這個跨來源請求。**如果 server 允許這個跨來源請求,它可以「授權」給這個來源的 JavaScript 存取這個資源。**
### CORS規範裡,跨來源請求分兩種
1. **簡單**跨來源請求
- HTTP方法只能是
- `GET`
- `POST`
- `HEAD`
- 自訂的 `request header` 只能是
- `Accept`
- `Accept-Language`
- `Content-Language`
- `Content-Type`(值只能是 `application/x-www-form-urlencoded`、`multipart/form-data` 或 `text/plain`)
2. **不簡單**跨來源請求
- 違反以上兩點條件的就屬之
- ex: `PUT`、`DELETE`、 `Content-Type: application/json`
### 一般跨來源請求瀏覽器會先發出預檢請求
>不簡單的跨來源請求就是一般的跨來源請求,**瀏覽器在發送請求之前會先發送一個 「preflight request(預檢請求)」**,**其作用在於先問伺服器:你是否允許這樣的請求?**
預檢請求:
1. 是一個http `OPTIONS`方法。
2. 帶有兩個 request header:
- `Access-Control-Request-Method`
- `Access-Control-Request-Headers`
**Server收到預檢請求之後,Server 必須告訴瀏覽器:我允許的方法和 header 有哪些**。回應需帶有以下兩個header
1. `Access-Control-Allow-Methods`: 允許的 HTTP 方法。
2. `Access-Control-Allow-Headers`: 允許的非「簡單」header
### 跨來源請求的cookies
1. **跨來源請求預設是不能帶 cookies 的!! (考量資安)**
2. server端需額外設定: `Access-Control-Allow-Credentials: true`

* [[教學] CORS 是什麼? 如何設定 CORS?](https://shubo.io/what-is-cors/#tldr)