---
# System prepended metadata

title: Node.js

---

# Node.js
## 目錄
[TOC]
## 1、Node.js 介紹
### <i class="fa fa-arrow-circle-right"></i> V8 JavaScript引擎
1. Google團隊所開發
2. Chrome內含V8
3. 解讀執行JavaScript程式
#### 【補充】deno v.s. node.js
{%youtube M3BM9TB-8yA %}
[Node.js 開發之父：「十個Node.js 的設計錯誤」](https://m.oursky.com/node-js-%E9%96%8B%E7%99%BC%E4%B9%8B%E7%88%B6-%E5%8D%81%E5%80%8Bnode-js-%E7%9A%84%E8%A8%AD%E8%A8%88%E9%8C%AF%E8%AA%A4-%E4%BB%A5%E5%8F%8A%E5%85%B6%E7%B5%82%E6%A5%B5%E8%A7%A3%E6%B1%BA%E8%BE%A6%E6%B3%95-f0db0afb496e)

### <i class="fa fa-arrow-circle-right"></i> [Node.js](https://github.com/nodejs/node)架構介紹
* Node.js主要是來做後端的
* 後端開發
    * php
    * Java
    * Python
    * ASP.NET
* Node.js優勢
    1. 性能
    2. 與前端JavaScript配合方便
    3. Node.js方便前端學習
* [node原始碼](https://github.com/nodejs/node)
    * deps→Node.js用到的插件
    * src→Node.js仰賴V8寫的C++程式 (可以當作Node.js的核心程式碼)
    * lib→Node.js的API

### <i class="fa fa-arrow-circle-right"></i> 命令提示字元操作
#### 電腦裡的終端機(命令提示字元)
* Mac: terminal.app (ctrl+空白 搜尋 terminal)
* Win: cmd.exe (開始→尋找 cmd)
    * ConEmu、Cmder
    * win 10 / win 11 Microsoft Store - [terminal](https://www.microsoft.com/store/productId/9N0DX20HK701) 
#### 熟悉指令
1. 移動路徑
```bash
cd 移動路徑
```
2. 回到上一層
```bash
cd ..
```
3. 瀏覽所在目錄
* Win
```bash
dir
```
* Mac
```bash
ls
```

### <i class="fa fa-arrow-circle-right"></i> 安裝[Node.js](https://nodejs.org/en/)
* node起手式指令
1. 查詢node.js版本
```bash
node --version
```

### <i class="fa fa-arrow-circle-right"></i> 使用Node.js開啟編譯核心
```bash
node
```
進入到node.js編譯核心，可以在指令列中直接撰寫JavaScript (就像是打開Chrome瀏覽器的console功能寫JavaScript)
* 離開此模式
    * `Ctrl+C`兩次

### <i class="fa fa-arrow-circle-right"></i> 透過Node.js執行js檔案
```bash
node js檔案名稱(含副檔名)
```

### <i class="fa fa-arrow-circle-right"></i> 使用VS Code執行與除錯Node.js

## 2、Node模組原理
### <i class="fa fa-arrow-circle-right"></i> Global全域物件
#### Window
* 開啟網頁就會有一個Window的全域物件

#### Global (與Window物件概念相同)
* 對應開js檔案所繼承的資料
* 變數要被Global繼承必須要寫成
```javascript
Global.a = 1;
//以下寫法並不能被Global繼承
//此變數僅在該js裡使用
//原因是Node.js設計上就是一個js檔案就是一個模組，所以不允許模組汙染到Global
var a = 1;
```

### <i class="fa fa-arrow-circle-right"></i> VS Code執行Node.js應用程式
* VS Code有整合終端機功能
    * 檢視→整合終端機

### <i class="fa fa-arrow-circle-right"></i> require、module exports模組設計
* app.js
```javascript
var a = 1;
console.log(a);
console.log(data);
```
* data.js
```javascript
var data = 2;
```
如果在`app.js`中`console.log(data)`是不會印出2
* 因為node.js==模組化規則==很嚴格
---
#### 修改1
* app.js
```javascript
var content = require('./data');
var a = 1;
console.log(a);
console.log(content);
```
* data.js
```javascript
var data = 2;
```
**此時會印出**
```bash
1
{}
```
---
#### 修改2
* app.js
```javascript
var content = require('./data');
var a = 1;
console.log(a);
console.log(content);
```
* data.js
```javascript
var data = 2;
module.exports = data;//
```
**此時會印出**
```bash
1
2
```
#### module.exports導出模組資料

### <i class="fa fa-arrow-circle-right"></i> exports模組設計
```javascript
exports.data = 2;
//等同以下寫法
module.exports = {
    data = 2
}
```
* 也可以是一個`function`
```javascript
exports.data = 2;
exports.bark = function(){
    return 'bark!!!';
}
```
:::info
`exports`與`module.exports`不能混用會互相覆蓋
:::

### <i class="fa fa-arrow-circle-right"></i> Node核心模組http - createServer
```javascript
var http = require('http');//載入(引用)node.js http模組
http.createServer(function (request,response) {
    //request   當使用者讀取到網站時，就會發送瀏覽請求並且提供相關資料
    //response  收到資料，回傳資料
    response.writeHead(200,{"Content-Type":"text/plain"});
    response.write('Hello');
    response.end();
}).listen(8080);
//ES6寫法
const http = require('http');
http.createServer((req,res) =>{
    console.log('有人來訪問我了');
});
```
#### 監聽 - 等著
```javascript
const http = require('http');
var server = http.createServer(function(request,response) {
    console.log('有人來訪問我了');
});
//監聽-等著
//端口-數字
server.listen(8080);
```
#### request  請求    (輸入-請求的訊息)
> request.url

#### response 響應    (輸出-輸出給瀏覽器的東西)
```javascript
response.write();
response.end();
```
#### port(通訊埠)
* `127.0.0.1` or `localhost`用自己電腦所開啟的web server
    * 開啟自己電腦內部的伺服器

### <i class="fa fa-arrow-circle-right"></i> __dirname、__filename
#### __dirname
#### __filename

### <i class="fa fa-arrow-circle-right"></i> Node模組-path
```javascript
var path = require('path');
// 抓目錄路徑
console.log(path.dirname('/xx/yy/zz.js'));  // 回傳 /xx/yy 
// 路徑合併
console.log(path.join(__dirname,'/xx'));    // 回傳 前後路徑合併
// 抓檔名
console.log(path.basename('/xx/yy/zz.js')); // 回傳 zz.js
// 抓副檔名
console.log(path.extname('/xx/yy/zz.js'));  // 回傳 js
// 解(分)析路徑
console.log(path.parse('/xx/yy/zz.js'));    // 回傳 上述綜合物件
```
## 3、NPM (Node Package Manager)
### <i class="fa fa-arrow-circle-right"></i> 什麼是[NPM (Node Package Manager)](https://www.npmjs.com)
* 查詢npm版本
```bash
npm -v
```
### <i class="fa fa-arrow-circle-right"></i> npm init開發自己的package.json
#### package.json檔
* 新增package.json 
```bash
npm init
```

### <i class="fa fa-arrow-circle-right"></i> npm安裝流程
* 記得要先移動到**相對應的專案資料夾**中
```bash
npm install express --save
```
* Mac版本需要前面加`sudo`

### <i class="fa fa-arrow-circle-right"></i> npm版本號介紹
說明範例：1.12.0
*  1: 主要版本號
* 12:次要版本號
*  0: bug修正
* ^: 安裝次要、bug修正的版本     (1.x.x)
* ~: 安裝bug修正的版本          (1.12.x)
* 沒有任何符號：指定對應版本     (1.12.0)
* latest: 永遠都會載入最新的版本

### <i class="fa fa-arrow-circle-right"></i> npm install的妙用
* node_modules不會進入到版本控制    (忽略)
* 透過指令把dependencies中相對應的套件安裝回來
```bash
npm install
```

### <i class="fa fa-arrow-circle-right"></i> --save、--save-dev、-g差異
#### --save
`node`應用程式上線會用到的`npm`套件
* 能夠有效紀錄開發過程中所用到的套件
#### --save-dev
只是在開發過程中用來測試或除錯的套件(非主要模組)，不會影響你的應用程式上線功能
* devDependencies
#### -g (全域)
安裝路徑
> Win: C:\Users[使用者名稱]\AppData\Roming\npm\node_modules
> Mac: usr/local/lib/node_modules

### <i class="fa fa-arrow-circle-right"></i> 執行NPM內容流程
#### nodemon套件
```bash
nodemon 檔案名稱
```
在開發過程中可以不用一直輸入指令執行修改後的js檔

### <i class="fa fa-arrow-circle-right"></i> NPM常用指令小抄
* npm -v ：觀看 NPM 版本
* npm init ：新增 package.json
* npm install [模組名稱][安裝位置] ：安裝 NPM 模組，安裝位置常用屬性如下：
    * -g  全域安裝
    * --save  安裝模組並寫入 package.json 的 "dependencies"
    * --save-dev  安裝模組並寫入 package.json 的 "devDependencies"
* npm list ：顯示安裝的 NPM 列表
* npm uninstall [模組名稱] ：刪除專案裡的 NPM

## 4、Node除錯
### <i class="fa fa-arrow-circle-right"></i> log探索 
### <i class="fa fa-arrow-circle-right"></i> Node內建除錯模組
```javascript
var a = 1;
var b = 1;
var c = 1;
```
```bash
node debug js檔案名稱
```
* n     (next的意思)
* repl  (在debug模式下觀察上下文環境內容)
* ctrl+c結束
```javascript
var a = 1;
var b = 1;
var c = 1;
debugger
a = 3;
a = 4;
debugger
```
* c     (cont)跳到debugger那行去

### <i class="fa fa-arrow-circle-right"></i> node內建chrome dev tools
```bash
node --inspect --debug-brk js檔案名稱
```
* --inspect 
開啟chrome去看當下js的狀態
* --debug-brk
可以中斷在程式第一行的位置上
* 複製chrome-devtools:...，貼到chrome瀏覽器中

### <i class="fa fa-arrow-circle-right"></i> VS Code進階除錯

### <i class="fa fa-arrow-circle-right"></i> VS Code定義瀏覽
* 移至定義
* 預覽定義

## 5、LINE Bot機器人開發
### 參考資料
- [建立 LINE Channel](https://steam.oxxostudio.tw/category/python/example/line-developer.html) 
- [什麼是 Webhook？](https://steam.oxxostudio.tw/category/python/example/line-webhook.html)
### 開發準備
- [LINE Developers](https://developers.line.biz/zh-hant/)
-  [LINE 官方帳號](https://tw.linebiz.com/login/)
- 開發套件 [Bottender](https://bottender.js.org/)
- 讓外網連接伺服器[ngrok](https://ngrok.com)
- API 工具 [Postman](https://www.postman.com/)
### 1. 登入LINE Developers建立Provider
![image](https://hackmd.io/_uploads/SJWlq-VN0.png)
- 第一次登入的話應該會是空的
![image](https://hackmd.io/_uploads/S1R49ZN4A.png)
- 點擊Create New Provider
    - 輸入Provider name
    ![image](https://hackmd.io/_uploads/H10Da8NVC.png)
    - 選擇要建立的Channel (選擇 `Create a Messaging API channel`)
        - LINE Login
        - Messaging API
        - Blockchain Service
        - LINE MINI App
    ![image](https://hackmd.io/_uploads/Sk75ALE4A.png)
    - 輸入相關必要資訊
    - 建立完成後可以再對應的Provider看到Channel
    ![image](https://hackmd.io/_uploads/ry9RRIEER.png)
:::warning
補充說明：
建立完Messaging API後，LINE現在會自動使用該Channel的名稱建立一個官方帳號，所以不用自己建。
如果發現官方帳號的地方，沒有出現跟Messaging API這個Channel名稱一樣的官方帳號，請同學執行底下第2個步驟
:::
### 2. 登入[LINE Official Account](https://tw.linebiz.com/login/)建立官方帳號
- 選擇**LINE官方帳號管理頁面**→**登入管理頁面**
    ![2024_05_29_15_55_58_LINE_官方帳號管理頁面_LINE_Biz_Solutions](https://hackmd.io/_uploads/r19YxvN40.jpg)
- 建立官方帳號 (填寫相關資訊)
- 官方帳號建立完成後，可以在【帳號一覽】中看到建立好的官方帳號
    ![image](https://hackmd.io/_uploads/H1CzbPVN0.png)
- 點擊進入建立好的官方帳號
    ![image](https://hackmd.io/_uploads/rkkKZwEVC.png)
- 選擇【自動回應訊息】，【關閉】自動回應訊息的狀態，避免每次跟 LINE BOT 聊天時，都會跳出自動回應的訊息。
    ![2024_05_29_16_06_13_LINE_Official_Account_Manager](https://hackmd.io/_uploads/rk2QGP44R.jpg)
- 點選右上角【設定】進入設定頁面 → 選擇左邊選單中的 【Messaging API】
    ![image](https://hackmd.io/_uploads/SyitzvNN0.png)
- 點選【啟用Messaging API】 → 選擇第一步驟建立好的服務提供者 (Provider)
    ![image](https://hackmd.io/_uploads/SyMZmwNEC.png)

### LINE BOT 與 Webhook 的關係 
- 參考圖
![image](https://hackmd.io/_uploads/rJkWIv4ER.png)
- 當使用者在 LINE 聊天室裡跟 LINE BOT 聊天，會發生下列的步驟：
    - Step 1：向使用 Message API 所建立的 LINE BOT 發送訊息。
    - Step 2：訊息透過 Webhook 傳遞到使用者部署 Python 程式的伺服器。
    - Step 3：根據 後端伺服器程式的邏輯，處理訊息。
    - Step 4：透過 Webhook 回傳結果到 LINE BOT。
    - Step 5：LINE BOT 發送訊息到 LINE 聊天室裡。

### 建立後端程式 (Webhook)
- 複製bottender-express程式道專案資料夾
- 執行`npm install`
- 修改bottender.config.js
    ```javascript=
        module.exports = {
          channels: {
            messenger: {
              enabled: false,
              path: '/webhooks/messenger',
              pageId: process.env.MESSENGER_PAGE_ID,
              accessToken: process.env.MESSENGER_ACCESS_TOKEN,
              appId: process.env.MESSENGER_APP_ID,
              appSecret: process.env.MESSENGER_APP_SECRET,
              verifyToken: process.env.MESSENGER_VERIFY_TOKEN,
            },
            line: {
              enabled: true,
              path: '/webhooks/line',
              accessToken: process.env.LINE_ACCESS_TOKEN,
              channelSecret: process.env.LINE_CHANNEL_SECRET,
            },
            telegram: {
              enabled: false,
              path: '/webhooks/telegram',
              accessToken: process.env.TELEGRAM_ACCESS_TOKEN,
            },
            slack: {
              enabled: false,
              path: '/webhooks/slack',
              accessToken: process.env.SLACK_ACCESS_TOKEN,
              verificationToken: process.env.SLACK_VERIFICATION_TOKEN,
            },
            viber: {
              enabled: false,
              path: '/webhooks/viber',
              accessToken: process.env.VIBER_ACCESS_TOKEN,
              sender: {
                name: 'xxxx',
              },
            },
          },
        };

    ```
- 設定.env檔案中的`LINE_ACCESS_TOKEN`以及`LINE_CHANNEL_SECRET`
    - LINE_ACCESS_TOKEN
        - LINE Developers → 選擇對應的Channel → 選擇Messagning API頁籤拉到最下面有一個`Channel access token`，點選Issue產生出一串文字金鑰
        - 將那串文字複製起來貼到.env的LINE_ACCESS_TOKEN後面
    - LINE_CHANNEL_SECRET
        - LINE Developers → 選擇對應的Channel → 選擇Basic setting頁籤
        - 找到Channel secret將金鑰文字複製起來貼到.env檔案的LINE_CHANNEL_SECRET後面
    ```env=
        MESSENGER_PAGE_ID=
        MESSENGER_ACCESS_TOKEN=
        MESSENGER_APP_ID=
        MESSENGER_APP_SECRET=
        MESSENGER_VERIFY_TOKEN=

        LINE_ACCESS_TOKEN=h5XPHUQTn5Tz9/F4+WC1dzXE0r/ObCRIyUYd+T79FigMII4vtZyd2VvPukqq5+JWt2U7fSKCGZoOGndx14XiuBje7vmQWrONBxWrwr6bV0Kq1KtQH3tW/rUKZy7sL3sypPlnrJwf+spKeR5/C7jGizdvdsvszcfbsfvbv
        LINE_CHANNEL_SECRET=69b32c7e8636c2vadvadvadvf325989c2

        TELEGRAM_ACCESS_TOKEN=

        SLACK_ACCESS_TOKEN=
        SLACK_VERIFICATION_TOKEN=

        VIBER_ACCESS_TOKEN=

    ```
- 執行程式
    ```bash=
    npm run dev
    ```
### ngrok
- [註冊帳號](https://dashboard.ngrok.com/signup)
- 完成註冊後登入，進入到帳號主控台頁面，左側選擇【Your Authtoken】
    ![2024_05_30_11_37_02_](https://hackmd.io/_uploads/HkuiVdrV0.jpg)
- 執行ngrok.exe將紅色框起來地方的程式複製貼進去執行
    ![2024_05_30_11_38_54_](https://hackmd.io/_uploads/HJ8-BdH4A.jpg)
- 執行完畢後輸入以下程式
    ```bash=
    ngrok http 5000
    ```
### 設定Webhook
1. 請同學到LINE Developers選擇建立好的Provider的Messaging API Channel
2. 將ngrok所產生出來的網址加上`/webhooks/line`，例如`https://xxx.xxx.xxx/webhooks/line`
3. 在Webhook URL的地方把上述網址貼上
4. Use webhook記得要打開
![2024_06_06_09_16_42_](https://hackmd.io/_uploads/HkTZycRNR.jpg)




### 3. 程式串接與撰寫（使用Bottender、ngrok)
#### index.js
```javascript=
module.exports = async function App(context) {
  let userInfo = await context.getUserProfile();
  const userName = userInfo.displayName;
  if (context.event.isText) {
    // handling the text message event
    // console.log(`user info: ${JSON.stringify(userInfo)}`);
    let jsonObj = {
      "type": "carousel",
      "contents": [
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B27_sl9rv9Hs1G.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "陳夏宗 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "shiachun@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21C11_j9Me4vCfFU.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "許政行 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "chhsu@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_baCL7oICh3.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "康淵 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "yk@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_6F6jP39wom.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "鍾文仁 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "wenren@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_4ZHU29sjXu.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "丁鏞 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "yung@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_v12kVehuaS.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "張耀仁 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "justin@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_jjL041ZS8e.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "陳冠宇 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "gychen@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_6RKPS0lwmo.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "范憶華 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "yihuafan@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        }
      ]
    };
    let jsonObj2 = {
      "type": "carousel",
      "contents": [
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_WjkRCaWpY7.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "李有璋 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "yclee@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B25_eiQgDNp8CQ.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "翁輝竹 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "hcweng@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_XeccGWymN5.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "黃信行 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "hhh@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_kieyumNnqO.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "吳政達 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "nanowu@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_8BHUeGF7iL.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "廖川傑 教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "chuanchiehliao@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_wEqdEN87mx.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "林明璋 副教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "mclin@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_ekYkM8gaEH.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "胡聖彥 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "shengyenhu@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_BCNYxN2mEQ.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "杜哲怡 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "ann@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        }
      ]
    };
    let jsonObj3 = {
      "type": "carousel",
      "contents": [
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_tKoL6Ybsdc.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "魏福勝 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "harrywey@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_d7gtYv2UhK.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "李汶墾 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "wenkenli@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21B24_lzO72hXEED.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "黃建勝 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "jshuang@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_21H02_SeeP0NgnN8.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "丁郁宏 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "august@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_23A18_pmpQS8XCNb.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "鄭年添 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "tonycheng@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        },
        {
          "type": "bubble",
          "size": "micro",
          "hero": {
            "type": "image",
            "url": "https://cycu-me.org/upload/fac_member_list_pic/twL_fac_member_24A29_RqNx223iiD.jpg",
            "size": "full",
            "aspectMode": "cover",
            "aspectRatio": "320:213"
          },
          "body": {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "text",
                "text": "簡育欽 助理教授",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              },
              {
                "type": "text",
                "text": "ycchien@cycu.edu.tw",
                "weight": "bold",
                "size": "sm",
                "wrap": true
              }
            ],
            "spacing": "sm",
            "paddingAll": "13px"
          }
        }
      ]
    };
    if(context.event.text ==`機械系老師`) {
      await context.sendFlex('中原機械教師1', jsonObj);
      await context.sendFlex('中原機械教師2', jsonObj2);
      await context.sendFlex('中原機械教師3', jsonObj3);
    } else {
      await context.sendText(`${userName}您好！我收到你的文字【${context.event.text}】`);
    }
  } else {
    await context.sendText('我不吃文字以外的資料！');
  }
  
};
```
#### Flex Message
-[Flex Message Simulator](https://developers.line.biz/flex-simulator/)

## 6、Google Firebase
### <i class="fa fa-arrow-circle-right"></i> Firebase服務介紹
* [Firebase官方網站](https://firebase.google.com/)
* [Firebase資料庫官方文件](https://firebase.google.com/docs/reference/js/firebase.database.Reference?hl=zh-tw)

### <i class="fa fa-arrow-circle-right"></i> 環境介紹

### <i class="fa fa-arrow-circle-right"></i> 資料庫環境設定

### <i class="fa fa-arrow-circle-right"></i> ref(路徑)、set(新增)
* firebase全部都是物件格式，不能陣列內容
```javascript
var data = null;
data = {
    student1:{
        name: 'Tom',
        num:'1'
    },
    student2:{
        name: 'John',
        num:'2'
    }
};
```
#### set新增
寫入資料庫的內容可以是**文字**也可以是**物件**

#### ref路徑  (類似mongoDB的collection或是SQL的資料表)
* ref()沒有內容即為根目錄
* ref('第一層/第二層/...')可以修改對應層級資料

#### 資料庫的設計 (以餐廳為例)
* 盡量扁平一點不要寫太多層級
```javascript
var data = null;
data = {
    food:{
        coke:{
            price:30,
            num:1
        },
        fries:{
            price:50,
            num:20
        }
    },
    order:{
        1:{
            coke:2
        },
        2:{
            fries:5,
            coke:2
        }
    }
};
```

### <i class="fa fa-arrow-circle-right"></i> 顯示資料
* firebase的程式要放到body中
#### once 讀取一次資料庫的資料
```javascript
 var myName = firebase.database().ref('myName');
// once 讀取一次資料庫的資料
// on   隨時監聽
myName.once('value',function(snapshot){
    console.log(snapshot.val());
    var str = snapshot.val();
    document.getElementById('title').textContent = str;
});
```
#### on 隨時監聽(資料即時呈現)

### <i class="fa fa-arrow-circle-right"></i> firebase非同步觀念

### <i class="fa fa-arrow-circle-right"></i> push - 新增資料
```javascript
var todos = firebase.database().ref('todos');
todos.push({content:'今天要記得刷牙'});
```

### <i class="fa fa-arrow-circle-right"></i> remove、child移除資料
#### child找出當下的子路徑
```javascript
var todos = firebase.database().ref().child('todos');   //找到根目錄底下的子目錄
```
#### remove 刪除資料

### <i class="fa fa-arrow-circle-right"></i> for-in語法
```javascript
var colors = ['red','black','yellow'];
// 一般for迴圈寫法
for (var i = 0; color.length > i; i++)
{
    console.log(color[i])
}
// for in 寫法
// item會依序撈出陣列索引值
// for (variable in [ object | array])
// {
//      statements
// }
for(var item in colors){
    console.log(item);
}
//結果會是0 1 2
```
* 陣列物件
```javascript
var kaohsiung = [
    {
        father:'Tom',
        mon:'Mary'
    },
    {
        father:'John',
        mom:'Jane'
    }
];
for (var item in kaohsiung){
    console.log(kaohsiung[item].father);
}
```
* 物件
    * item會是物件屬性
```javascript
var todos = {
    num1:{
        content:'要記得刷牙'
    },
    num2:{
        content: '要記得洗澡'
    }
};
for (var item in todos){
    console.log(item);
}
// 結果會是 num1、num2
// 要撈出content
// todos[item].content
```

### <i class="fa fa-arrow-circle-right"></i> 網頁上即時瀏覽firebase資料
```javascript
var ref = firebase.database().ref();
ref.on('value',function(snapshot){
    var results = JSON.stringify(snapshot.val(), null, 3);
});
```

### <i class="fa fa-arrow-circle-right"></i> 排序
* orderByChild
* 需搭配forEach語法
```javascript
var peopleRef = firebase.database().ref('people');
peopleRef.orderByChild('weight').once('value',function(snapshot){
    snapshot.forEach(function(item){
        console.log(item.key);  // item.key可以得到父屬性值
        console.log(item.val());
    });
});
```
> 抓路徑→排序('屬性')→讀取內容→forEach 依序撈出資料
#### 排序規則
1. 指定子鍵為null的子項目排在最前面
2. 指定子鍵值為false的子項目
3. 指定子鍵值為true的子項目
4. 指定子鍵值為數值，按升序排序
5. 指定子鍵值為字串
6. 指定子鍵值為物件

### <i class="fa fa-arrow-circle-right"></i> 過濾(搜尋規則)
> 抓路徑→排序('屬性')→過濾→讀取內容→forEach 依序撈出資料
* startAt() 多少以上
* endAt() 多少以下
* equalTo() 相等

### <i class="fa fa-arrow-circle-right"></i> 限制筆數 limit
> 抓路徑→排序('屬性')→過濾→限制筆數→讀取內容→forEach 依序撈出資料
* limitToFirst()   從最前面開始撈出資料
* limitToLast()    從最後面開始撈出資料

### <i class="fa fa-arrow-circle-right"></i> 時間篇
```javascript
var time = new Date();
consolelog(time);
consolelog(time.getFullYear());
consolelog(time.getMonth());        //在JavaScript中，0 = 1月
consolelog(time.getDay());          //在JavaScript中，禮拜天 = 0
consolelog(time.getHours());
consolelog(time.getMinutes());
consolelog(time.getSeconds());
consolelog(time.Milliseconds());    // 1000毫秒 = 1秒
```
* timestamp (時間戳記，時戳)
* UNIX時間 - 格林威治時間(GTM)1970年1月1日00:00：00到目前經過的秒數
```javascript
var time = new Date();
time.getTime();             //將帶有日期格式的時間轉換成UNIX時間
var now = new Date(time);   //將UNIX時間轉換回帶有日期的格式
```

### <i class="fa fa-arrow-circle-right"></i> reverse資料翻轉調整
```javascript
var data = [1, 2, 3, 4, 5];
data.reverse();// 將資料反轉
// 將物件加入陣列後進行reverse反轉排序
var data = [];
var todos = {
    1234: {
        content: 'hello'
    },
    456: {
        content: 'hi'
    }
};

```
## 7、Node.js後端 - Express框架
### <i class="fa fa-arrow-circle-right"></i> Express框架介紹
* Node.js Web應用框架
* 輕量型 Web 應用框架
* 後端邏輯
    * AJAX post
    * EJS template、jade(pug)

### <i class="fa fa-arrow-circle-right"></i> Express環境安裝
* Win
```bash
npm install express --save
```
* Mac
```bash
sudo npm install express --save
```

### <i class="fa fa-arrow-circle-right"></i> 開啟Web伺服器
* 透過Express建立Web伺服器
    * app.js
```javascript
var express = require('express');
var app = express();

app.get('/', function(request, response){
    res.send('');
});
//監聽 port
var port = process.env.PORT || 3000;
app.listen(port);
```
* process.env.PORT
    * 環境預設port

### <i class="fa fa-arrow-circle-right"></i> 網址規則
#### Router路由
* https、http協定
    * https有加密
* domian網址
    * www.google.com.tw
    * 127.0.0.1 →本地端
    * www.cycu.edu.tw
* 路徑
* 參數(query) 
    * ?參數1=&參數2=&....

### <i class="fa fa-arrow-circle-right"></i> Router路由設計

### <i class="fa fa-arrow-circle-right"></i> 取得指定路徑(params)
> 網址 https://www.xxx.xxx/**:路徑參數名稱**
> request.params.參數名稱
```javascript
app.get('/user/:name', function(req,res){
    var myName = req.params.name;
});
```

### <i class="fa fa-arrow-circle-right"></i> 取得網址參數(query)
> 網址 https://www.xxx.xxx/參數名稱**?網址參數1&網址參數2**
> request.query.網址參數名稱
```javascript
//範例：某某人的音樂列表，抓前10筆
app.get('/user/:name', function(req,res){
    var myName = req.params.name;
    var limit = req.query.limit;
});
```

### <i class="fa fa-arrow-circle-right"></i> Middleware - 中介軟體
```javascript
var express = require('express');
var app = express();
//app.use像是個守門員，要顧及網站安全，必須在前面
app.use(function(req,res,next){
    console.log('有人進來了');
    //確保沒問題next()進入到下一個關卡(程式)
    next();
});
```
#### 404路由設定
* 頁面不存在
```javascript
app.use(function(req,res,next){
    res.status(404),send('抱歉，您的頁面找不到');
});
```
#### 500路由設定
* 程式錯誤
```javascript
app.use(function(err,req,res,next){
    console.log(err.stack);
    res.status(500).send('程式有些問題，請稍後嘗試');
});
```
#### 不同寫法
```javascript
// Way 1
var login = function(req,res,next){
    console.log('你是登入狀態');
    next();
};
app.use(login);
// Way2
var login = function(req,res,next){
    console.log('你是登入狀態');
    next();
};
// 給單獨router使用
app.get('/',login,function(req,res,next){

})
```

### <i class="fa fa-arrow-circle-right"></i> 載入靜態檔案 (static)
> app.use(express.static('資料夾名稱'));
* 專案中必須要有對應的資料夾名稱
* 必須寫在最前面，這樣才可以抓到檔案
* 檔案的位置會以該**資料夾為根目錄**往下抓
```javascript
var express = require('express');
var app = express();
// 增加靜態檔案的路徑
// 我要把所有靜態檔案增加到public資料夾上
// 專案中要有public資料夾
// 必須寫在最前面的位置
app.use(express.static('public'));
```

### <i class="fa fa-arrow-circle-right"></i> Template - EJS語言介紹
#### 樣板語言
#### 環境安裝
```bash
npm install ejs-locals --save
```
```javascript
var engine = require('ejs-locals');
app.engine('ejs',engine);       // Express載入ejs作為樣板控制的
app.set('views','./views');     // app.set()設定Express各種設定，這裡是設定ejs檔案路徑位置
app.set('view engine','ejs');   // 指定Expess要用哪一個樣板引擎去跑
```
* xxx.ejs
    * res.render('ejs檔案名稱(不用帶附檔名)');

### <i class="fa fa-arrow-circle-right"></i> 參數導入
* app.js
```javascript
app.get('/',function(req,res){
    res.render('index', 
    {
        'title':'六角學院',
        'boss': 'AT'
    });
});
```
* index.ejs
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <%= title %> <!-- =是要轉成字串 -->
    <h2><%= boss %></h2>
</body>
</html>
```

### <i class="fa fa-arrow-circle-right"></i> EJS載入內容種類
* <%= %>渲染成字串
* <%- %>渲染成html格式
* <% %> 程式邏輯 
```html
<% if() { %>
    <span></span>
<% } %>
<% else { %>
    <span></span>
<% } %>
```

### <i class="fa fa-arrow-circle-right"></i> EJS載入陣列
```html
<% for (var i=0; course.length;i++) { %>
    <li><%- course[i] %></li>
<% } %>
```

### <i class="fa fa-arrow-circle-right"></i> EJS設定Layout
* layout.ejs
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <%- body %>
</body>
</html>
```
* index.ejs
```html
<% layout('layout') %>
<%= title %> <!-- =是要轉成字串 -->
<h2><%= boss %></h2>
```

### <i class="fa fa-arrow-circle-right"></i> API管理工具
#### API設計
- AJAX get、post向後端傳遞資料
* [postman](https://www.getpostman.com/)

#### Postman取得get資料、基礎操作
##### 使用postman傳送表單資訊
* 選擇POST
* body
    * 類型選x-www-form-urlencoded
    * key→控制項name
    * value→控制項中的值

### <i class="fa fa-arrow-circle-right"></i> body-parser取得表單資料
* body-parser套件
* 可以把前端表單的資料傳送到後端
```bash
npm install body-parser --save
```
```javascript
var bodyParser = require('body-parser');
//增加body解析
app.use(bodyParser.json());
app.use(bodyParser,urlencoded({
    extended:false
}));
```
```html
<form action="路徑" method="post">
    <!-- name屬性很重要!!!資料傳送到後端去，會以name作為名稱 -->
    <input type="text" name="" value="" >
    <input type="submit" name="" value="Button">
<form>
```
* req.body //解析內容

### <i class="fa fa-arrow-circle-right"></i> Redirect跳轉網頁設定
```javascript
// 轉址到某頁面去
res.redirect('頁面名稱');
// 會把該頁面名稱渲染到當前的router上
res.render('頁面名稱');
```

### <i class="fa fa-arrow-circle-right"></i> POST AJAX前後端介接原理

### <i class="fa fa-arrow-circle-right"></i> POST AJAX JSON格式
```javascript
var data = JSON.stringify({"content":str}); // 必須將JSON字串化
```
* 使用Postman測試
    * body選raw
    * 選JSON(application/json)

### <i class="fa fa-arrow-circle-right"></i> Router 進階設定
* 將各個邏輯放到各個route js檔中
* app.js僅需要load相關模組
```javascript
// app.js
app.use('/user',user);
// routes/user.js
// 路徑就會為 http://domain/user/edit-profile
router.get('/edit-profile', (req,res) =>{});

```

### <i class="fa fa-arrow-circle-right"></i> [express-generator](http://expressjs.com/zh-tw/starter/generator.html)
#### Express應用程式產生器
* 可以快速建立應用程式架構
```bash
npm install express-generator -g
```
* 建立應用程式
```bash
 express [options][dir]
```
#### 產生的結構
* bin
    - www
* public
    - javascript
    - images
    - stylesheets
        - style.css
* routes
    - index.js
    - users.js
* views
    - error.ejs
    - index.ejs
* app.js
* package.json

## 7、
### <i class="fa fa-arrow-circle-right"></i> 後端RESTful API

### <i class="fa fa-arrow-circle-right"></i> 前端設計 SPA (Single Page Application)

## 8、
### <i class="fa fa-arrow-circle-right"></i> cookie、session講解
#### cookie
##### cookie簡介
* 能夠儲存資料在瀏覽器上的小型資料庫
* 能夠在client、server進行讀取、寫入
* 是由key/value方式組成，並由**分號**跟**空格**來隔開
* 可以設定失效時間，讓cookie在指定時間內消失
* Chrome: F12 → application可以看到cookie

##### cookie欄位介紹
* Name: 鍵(key)
* Value: 值(Value)
* Domain: 可存取該cookie的網域
* expires: 限制cookie有效期間
* path: 設定可以存取該cookie的路徑
* secure: 設定cookie是否要https網址才可以進行傳送

##### cookie client(瀏覽器)端寫法
* 寫入cookie
```javascript
document.cookie = "myName=tom";
```
* 寫入cookie，並加入過期時間
```javascript
document.cookie = "username=bob;expires=Mon, 04 Dec 2017 08:18:32 GMT;path=/";
```
* GMT時間
```javascript
new Date().toGMTString();
```
* 寫入cookie，設定10秒後失效
```javascript
document.cookie = "username=bob; max-age=10; path=/";
```

##### cookie server(伺服器)端寫法
* 安裝解析cookie NPM
```bash
npm install cookie-parser
```
* express寫入cookie，並加入相關設定(過期時間、httponly、path)
```javascript
res.cookie(name, value[,options]);
// 範例
res.cookie('name','Mary',{
    maxAge: 1000,
    httponly: true
});
```
* express讀取Client端cookie
```javascript
req.cookie.yourCookieName;
```
#### session
##### session簡介
* 儲存在伺服器的暫存資料，此暫存資料可放在記憶體或資料庫上
* session可在cookie上儲存一筆辨識你是誰的session id
##### session id
* 用到[express session](https://github.com/expressjs/session)套件
```bash
npm install express-session --save
```
```javascript
const session = require('express-session');
```