---
# System prepended metadata

title: '[後端概念] 負載均衡/Http Cache/CORS'
tags: [後端]

---

# [後端概念] 負載均衡/Http Cache/CORS

###### tags: `後端`


## 負載均衡(Load Balancer)

>一個可以把接收的資料分佈給其他機器的功能。好處是，當伺服器能力不足的時候，可以輕易的添加機器，而當其中一台伺服器壞掉的時候，也不會導致服務整個掛掉。

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

## 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 指定拿取：某個時間點以後有更改的資料。**




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

五、認證權杖`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) `，告訴用戶端，**沒有新版本，使用快取即可。**

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

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


* [新手坑：讓人又愛又恨的 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`

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


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