.st0{fill:#FFFFFF;}

後端開發 筆記 – 1 

 2024-03-12

By  Mason - 預計閱讀時間約  分鐘

Version Control 版本控制

Command Prompt 常用指令

CMD Command

cd

mkdir

type nel > "filename.txt"

cls

dir

Ctrl + C

Description

Change directory

Make a new directory

製作一個新的 filename.txt 檔案

clear screen

list directory content

強制終止任何正在執行的指令

Unix 常用指令

Unix Command

cd

mkdir

pwd

touch

ls

rm

rmdir

rm -rf


Description

Change directory

Make a new directory

Stands for "present working directory"

Create, change and modify timestamps of a file

list files or directories in directory

Remove file

Remove an empty directory

rf stands for remove forcefully; 

can be used to remove a non-empty directory

Git and GitHub

Git 對 Local Repository 的檔案有四種主要狀態:

    1. untracked:全新的檔案,Git 對它一無所知。如果我們用 git add <file> 之後,該檔案將變成:

    2. staged:Git 已經知道該檔案了 (tracked),準備 commit。如果我們用 git commit 之後,檔案將變成:

    3. unchanged:檔案自上次 commit 之後未更改。一旦修改了檔案,則檔案就變成:

    4. unstaged or modified:我們可以用 git add 再次讓它變成 staged 狀態。

工作流程:

git init

 - 在 work directory 中,用 git init 開始追蹤程式碼版本。

 - 此時在 work directory 中,會新增一個 .git 資料夾 (隱藏的檔案)。

git add filename

 - 將程式碼文件放到 staging area 上面,準備 commit。

git add . => 選擇 work directory 裡面的所有檔案

git add *.html => 選擇 work directory 裡面的所有副檔名為 html 的檔案

git commit -m "commit message"

 - 把 staging area 上的文件做 commit。程式碼的更動會被記錄到 Local Repository (.git 資料夾) 內。

git push -u origin master

 - 將 local repository 的所有內容都放到遠端伺服器 (GitHub)。

Git 指令

Git Command

git init

git config --list

git --version

git config -global user.name "name"

git config -global user.email "name"

git status


git add filename

git commit -m "commit message"

git rm --cached filename

git log

git branch branchName

git checkout branchName

git merge branchName



git remote add origin gitSSH 

(首次執行需此步驟)

git push -u origin master



git push


git clone gitSSH

git pull gitSSH


git remote set-url origin gitSSH


git remote remove origin

Description

Initialize an empty git repository

Display all configuration settings

Display the current version of Git

Set username

Set email address

Displays the state of the working directory and 

the staging area

Add files to staging area

Commit all files on staging area

Remove files from staging area

Review and read commit history

Create a new branch from current commit

Switch to another branch

Take the independent lines of development 

created by git branch and integrate them into a 

single branch

Connect to a remote repository in gitSSH and 

name the connection origin

Push the commits in the local branch named 

masterto the remote named origin. -u stands for 

upstream. 通常第一次登入時,會被要求登入 GitHub

Once we set the -u flag, we can use "git push"

command.

Get a working copy of the remote repository

Update that local copy with new commits from 

the remote repository

Set the remote connection named origin to a new

remote repository

Remove a connection called origin

.gitignore

 - 在 VS Code 中建立 .gitignore 此檔案,並將不想讓 Git 追蹤的檔案名稱寫入其中。

GitHub

 - 登入 GitHub

 - 新增 a new repository

Node.js

 - 能夠在伺服器端運行的開放原始碼、跨平台執行環境。

 - 內部採用 V8 JavaScript 執行引擎 (與 chrome 相同)作為核心引擎。

 - 在 terminal 端,輸入 node filename 來執行。

Module Wrapper

 - 在 node.js 當中,module 是指一組的程式碼,組織成簡單或複雜功能,可被用來與外部其它程式碼結合。

 - Modeule 可以是單個文件或多個文件與資料夾的集合。

 - 在執行 module 的程式碼之前,Node.js 將使用如下所示的函數包裝器來包裝它:

    ((function(exports, require, module, __filename, __dirname) {

       // Module code actually lives in here

    })();    // IIFE

    __dirname: directory name 資料夾名稱

    __filename:file name 文件名稱

例如:

let name = 10;

console.log(name);

內部包裹的樣子:

(function (exports, require, module, __filename, __dirname) {

    let name = 10;

    console.log(name);

})();

    優點:

        1. 讓 module 內部所定義的 global variable 變成 function scope,不會干擾到外部 global variable。(變數名稱一樣的話也不會受到影響)

範例:在工作目錄 (node practice) 裏面有兩個 JS 檔案:app1.js, app2.js

node practice

app1.js

require("./app2"); // 與 app2.js 連結並拿來使用

let name = 30; // global variable

console.log(name);

app2.js

let name = 10;

console.log(name);

在 terminal 輸入 node .\app1.js

結果為:

                10

                30

        2. 讓 module 內部的 JS 文件可以使用某些實用的變數,例如 module、exports 可以用來輸出本身的 module,而 require 可以用來獲得其他 module

        3. __filename, __dirname 等變數在開發上變的方便,因為兩者包含 module 的絕對路徑與資料夾路徑。

Node.js Modules

Node.js 的 modules 分成三種:

    1. 自己製作的 modules (Self-Made Modules)

    在 Module Wrapper 中提供的變數:

     - module 變數是一個物件,此物件包含此文件的內部訊息,包含 id, path, exports, parent, filename 等等資訊。

     - exports 是 module 物件的屬性,本身是一個 empty object。

     - require 是一個 function,可以讀取一個 JavaScript 文件,執行該文件,然後 return 這個文件的 export object。若讀取的是一個資料夾,則讀取該資料夾內的 index.js 文件,執行該文件,然後 return 這個文件的 Exports object。

範例:在工作目錄 (node practice) 裏面有三個 JS 檔案:app1.js, app2.js, app3.js

node practice

app1.js

let app2 = require("./app2");

let app3 = require("./app3");

app2.morning();

app3.lunch();

app2.evening;

app2.js

function morning() {

    console.log("早安你好");

}

function evening() {

    console.log("晚安你好");

}

exports.morining = morning;

exports.evening = evening;

app3.js

function lunch() {

    console.log("午餐時間");

}

exports.lunch = lunch;

在 terminal 輸入 node .\app1.js

結果為:

                早安你好

                午餐時間

                晚安你好

範例:在工作檔案 myfile.js 旁邊有一個 myModules 資料夾,裏面有四個 JS 檔案:app1.js, app2.js, app3.js, index.js,  

myModules

app1.js

l

app2.js

function morning() {

    console.log("早安你好");

}

function evening() {

    console.log("晚安你好");

}

exports.morining = morning;

exports.evening = evening;

app3.js

function lunch() {

    console.log("午餐時間");

}

exports.lunch = lunch;

index.js

let app1 = require("./app1");

let app2 = require("./app2");

let app3 = require("./app3");

exports.moring = app2.morning

myfile.js

let myModule = require("./myModules");

myModule.morning();  

在 terminal 輸入 node .\myfile.js

若讀取的是一個資料夾,則讀取該資料夾內的 index.js 文件,執行該文件,然後 return 這個文件的 Exports object。

結果為:

                早安你好

    2. Node.js 內建的 modules 

     - 可以直接拿來使用 => Node.js modules

file system (fs) 範例 1:(writeFile)

writeFile()

// app.js

const fs = require("fs");

fs.writeFile("myFile.txt", "今天天氣不錯", (e) => {

  if (e) throw e;

  console.log("文件已經撰寫完畢");

});

在 terminal 輸入 node .\app.js

結果為:

                文件已經撰寫完畢

新增了一個 myFile.txt 檔案,裏面內容為:今天天氣不錯

file system (fs) 範例 2:(readFile)

readFile()

// app.js

const fs = require("fs");

fs.readFile("myFile.txt", "utf8", (e, data) => {

  if (e) throw e;

  console.log(data);

});

在 terminal 輸入 node .\app.js

結果為:

                天天氣不錯

file system (fs) 範例 2:(readFile)

readFile()

// app.js

const fs = require("fs");

fs.readFile("myfffFile.txt", "utf8", (e, data) => {

  if (e) {

  console.log(e);

  }

  console.log(data);

});

在 terminal 輸入 node .\app.js

結果為: // 發生錯誤 //

[Error: ENOENT: no such file or directory, open 'D:\Node Modules\myfffFile.txt'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'D:\\Node Modules\\myfffFile.txt'
}
undefined

    3. 網路上第三方製作的 modules 

     - 可以透過 npm (node package manager) 下載來使用。

    NPM

    NPM 是 Node Package Manager,是 Node.js 預設的套件管理系統。 npm 會隨著 Node.js 自動安裝。透過 npm,我們可以在 CLI (Command-Line Interface)下指令,命令電腦從網路上下載別的開發者發佈到網路上的 node packages。

    Module 是指具有一些功能的單個 JavaScript 文件。Package 是一個資料夾,其中包含一個或多個 modules

    若我們希望目前的 work directory 可以使用 npm 來下載別的開發者發佈到網路上的 node packages,並且管理這些 packages,需要先做指令:

npm init

所有 npm 管理的 packages 可以在 package.json  的文件中找到名稱以及版本。

網站資源: npmjs.com

    NPM 指令語法:

npm install <package>

    若要安裝特定版本的 package,指令語法:

npm install <package>@<version>

    以上的 npm 安裝語法,都只會將package安裝在 work directory 中,名為 node_modules 的資料夾中。

    若使用 npm install -g <package> 則可以將 package 放到作業系統內部。這代表,我們可以在任何的work directory 內部使用這個 package。

下載 nodemon package:

nodemon 功能:當檔案修改並儲存之後 nodemon 會自動執行該檔案。

npm install -g nodemon

使用:

nodemon [your node app]

    用 -g 安裝的 package,其二進制的文件會被放入電腦的PATH 環境變量中 (也就是作業系統知道的某個地方)。因此,這種 package 可以在 shell 被直接使用,在Windows的 CMD 當中,或是 Mac 的 terminal 當中,都可以直接透過shell使用套件。

    當然,如果是資料夾內用需要用 require() 所取得的 package,則一定要在本地透過npm install <package> 的指令安裝。只有像 nodemon 這種透過 shell 執行的 package 適合使用 -g 做全域安裝。

IP

 IP位址(英語:IP Address,全稱 (Internet Protocol Address),又譯為網際網路協定位址,是網際協定中用於標識傳送或接收資料的裝置的一串數字。(相當於每個在網路上的電腦的地址)


常見的 IP 位址分為 IPv4 與 IPv6 兩大類,IP位址由一串數字組成。IPv4 為32位元長,通常書寫時以四組十進位數字組成,並以點分隔,如:172.16.254.1 ; IPv6 為128 位元長,通常書寫時以八組十六進位數字組成,以冒號分割,如:2001:db8:0:1234:0:567:8:1。


IPv4 中的每 8 個 digit 都會被轉換為 0 到 255 之間的整數;因此,IPv4 通常是168.1.7.0而不是10101000.00000001.00000111.00000000。用前者更容易讓人記憶。

根據 IPv4 地址的格式,全世界有多少個不同的設備可以同時上網?32 bits 可以製作出 2 的 32 次方個不同的IP地址,約43億。 但是,這個世界上大約有 72 億人,且每個人可能擁有超過1個與網路連接的設備,所以用 IPv4 地址的格式可能會有一天不夠用。


因此,IPv6 於 1990 年代引入;IPv6 使用 128 位元,將確保地球上的每一個人、裝置、都能夠擁有一個 IPv6 地址。

DNS

Domain Name System,縮寫:DNS ,是網際網路的一項服務。它作為將域名 (Domain Name) 和 IP 位址相互對映的一個分散式資料庫,能夠使人更方便地存取網際網路。

DNS 旨在讓人們記住域名,而不是無意義的數字。 例如,
記住 www.youtube.com 比記住 168.112.0.12 更容易。

Port

伺服器中的 port 是網路通訊連接時,邏輯上的端點 (endpoint),用於在伺服器和客戶端之間交換信息。每個 port 被分配一個唯一的數字來單獨識別它們。

一些最常用的端口及其相關的網絡協議是:

Port 號碼

20, 21


22


25

80

443

3389


用途

File Transfer Protocol (FTP). FTP is for transferring files between 

a client and a server.

Secure Shell (SSH). SSH is one of many protocols that create secure 

network connections.

Simple Mail Transfer Protocol (SMTP). SMTP is used for email.

Hypertext Transfer Protocol (HTTP).

HTTP Secure (HTTPS). All HTTPS web traffic goes to port 443.

Remote Desktop Protocol (RDP). RDP enables users to remotely

connect to their desktop computers from another device.

例如,若Google伺服器是 https://www.google.com,我們希望發出 HTTPs Request,則可以對著 https://www.google.com:443 發出請求,即可連線到 Google 伺服器上處理HTTPs 請求的port。因為沒有必要顯示,所以網址後面的 :443 通常在網頁瀏覽器上是看不到的。

另一方面,Google伺服器有著 24 小時不停止運作的腳本語言,在處理任何來自 port 443 的請求。

腳本的 Pseudocode 如下:
app.listen(20, () => {// return a file to client}) || 處理FTP請求
app.listen(25, () => {// return an email to client}) //處理SMTP請求
app.listen(443, () => {// return a webpage to client}) || 處理HTTPs請求

localhost:3000

在電腦網絡中,localhost (意為「本地主機」,指「這台電腦」)是給迴路網絡接口 (loopback) 的一個標準主機名,相對應的 IP 位址為 127.0.0.1 (IPv4)。在DN中,localhost 這個 domain name 會被換成 127.0.0.1。

我們可以在自己的電腦上面架設並且運行伺服器。當我們要使用同一台電腦連結到在自己的電腦上面伺服器,可以透過寄送請求到 localhost 到自己的電腦上,這就是迴路網絡接口 (loopback)。

通常我們在本機上的網頁伺服器,都是使用 port 3000 或是 8080 (但基本上,也可以設定任何 1000 到 9999 內的數字)。

HTTP Request and Response Header

HTTP Request 以及 Response的 基本規定格式如下:

■ Request-Line for HTTP Request, Status-Line for HTTP Response
■ Header
■ An empty line indicating the end of the header fields
■ Optionally a message section

一個基礎的 Get Request :

    Get /index.html HTTP/1,1

    Host: xxx.xxx.xxxx.xxx     // header

    <BLANK LINE>                  // 終止

如果網頁交出表格資料,且使用 GET request 的話,會是:(例如: <form method= "GET">)

    Get /index.html?name=mason&age=24 HTTP/1,1    // 資料在此

    Host: xxx.xxx.xxxx.xxx

    <BLANK LINE>   

Post request 內部有表格資料的話,會是:(例如: <form method= "POST">)

    POST /index.html HTTP/1,1

    Host: xxx.xxx.xxxx.xxx                                                               // header

    Content-Type: application/x-www-form-urlencoded        // header

    Content-Length: 27                                                                    // header

   

    filed1=value1&field2=value2       // 資料在此

帶有 cookie 設定的 request:

   Get /index.html HTTP/1,1    

    Host: xxx.xxx.xxxx.xxx                           // header

    COOKIES: session_id = aksdfsafii11    // header

    <BLANK LINE>   


一個基礎的 Response :

    HTTP/1,1 200 ok              //Status

    Content-Length: 1555                                             // header

    Content-Type: text/html; charset=ISO-8859-1    // header

   

    <!DOCTYPE html>

    <html>

    <body>

    ...            

帶有 cookie 設定的 response:

    HTTP/1.1 200 OK
    CONTENT-LENGTH: 200
    CONTENT-TYPE: text/html
    SET-COOKIES: session_id = ads fklasdklfjaslkd; fja; sdklfjalksd; fjadsklfjiawe


    <!DOCTYPE html>

    ...

網頁伺服器製作

範例 1:

const http = require("http");

const fs = require("fs");

// request object, response object

const server = http.createServer((req, res) => {

  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });

  if (req.url == "/") {

    res.write("歡迎來到我的網頁");

    res.end();

  } else if (req.url == "/anotherPage") {

    res.write("這是另一個頁面");

    res.end();

  } else if (req.url == "/myFile") {

    fs.readFile("myFile.html", (e, data) => {

      if (e) {

        res.write("存取html文件錯誤。。。");

        res.end();

      } else {

        res.write(data);

        res.end();

      }

    });

  } else {

    res.write("不存在的頁面");

    res.end();

  }

});

//  callback function with 2 parameters

server.listen(3000, () => {

  console.log("伺服器正在port3000上運行");

});

Express.js

 - Express.js 是針對 Node.js 的應用框架 (framework),建構在 Node.js 之上,其主要目的是為了對 Node.js 架設的後端伺服器簡化程式碼並且增加開發速度 (這就是為何 Express 叫做 Express)。

 - 要使用 Express,我們只需要在 work directory 中執行:

npm install express

在 work directory 安裝步驟:

            work directory >>> npm init >>> npm install express

Framework and Library

Framework 與 Library 是兩個開發者常用的詞彙。兩者並沒有學術上的定義,但基本的區別是:

    使用 Library 就像從頭開始建造你的家。房子可以按照你喜歡的任何風格建造,房間可以按照你喜歡的方式佈置和裝飾。

    Framework 就像買新房一樣。房子已經建好了,所以你不用擔心建築問題,但你不能選擇房子的格局以及房間的佈置方式。

在Library當中通常會提供許多的功能,開發者可以自行選擇所需的部分取用。例如:

    Bootstrap 是 HTML, CSS 的 Library。

    jQuery 是 JavaScript 的 Library。

    Flask 是 Python 的web framework,開發者必須要依照 Flask 的規則架構進行開發,沒有自行選擇架構的自由。

範例:在工作目錄 (express practice) 裏面有 2 個 JS 檔案:try1.js, tr2.js

express practice

try1.js

const try2 = require("./try2");

try2();


相較於 node.js 寫法:

try2.try2Function();

try2.js

function try2Function() {

  console.log("hello from try2");

}

module.exports = try2Function;


相較於 node.js 寫法:

module.exports.try2Function = try2Function;

在 terminal 輸入 node .\try1.js

結果為:

                hello from try2

網頁伺服器製作

const express = require("express");

const app = express();    // 物件 (代表伺服器)

// HTTP request, GET, POST, PUT, DELETE

app.get("/", (req, res) => {

  res.send("歡迎來到網站");

});


app.get("/anotherPage", (req, res) => {

  res.send("歡迎來到另一個頁面");

});


app.get("/example", (req, res) => {

  res.send("<h1>這是一個h1標籤的示範<h1>");

});


// 傳送 example1.html 頁面

app.get("/example1", (req, res) => {

  res.sendFile(__dirname + "/example1.html");

}); 


// 傳送 object

app.get("/object", (req, res) => {

  let obj = {

    title: "Web Design",

    website: "Udemy",

  };

  res.json(obj);

}); 


// 導向到別的頁面

app.get("/toexample", (req, res) => {

  res.redirect("/example");

}); 

// 當使用者輸入錯誤的網址,會呈現的內容 (需放在所有 rout 最下方)

app.get("*", (req, res) => {

  res.send("你所打的頁面不存在");

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器正在聆聽 port 3000...");

});

相較於 node.js 寫法,使用 express.js 的語法相對比較簡便!

HTTP Request Methods

 - HTTP 協議中,客戶端可以向伺服器發出請求(request)。常見的請求 method分成以下幾種:
    1. GET - 用於請求指定的資源。使用 GET 的請求只應用於取得資料。
    2. POST - 用於提交指定的資源,通常會改變伺服器的狀態或已儲存的資料。

    [以上兩種 request 可由 HTML 的 form 當中(method 屬性)傳送]


 - 我們在瀏覽器中輸入網址,請求網頁,都是在向伺服器發出 GET request 。

 - 當我們登入某個網頁時,則是發出 POST request。發出 GET request 時,額外的資訊會被放在 UR L的後面,用 ? 當作與端點的分隔符號& 為多個資訊間的分隔符號。發出 POST request 時,額外資訊則會被藏起來。

 - 其他常見的 request methods:
    1.
PUT - 用於修改資源的方法,客戶端發送更新整個資源的數據
    2.
PATCH - 用於修改資源的方法,客戶端發送要更新的部分數據而不修改整個數據
    3.
DELETE - 用於刪除資源。

    以上三種 HTTP request 皆無法從瀏覽器發送,只能使用程式語言或是 postman 等軟體發送。

Express Routing

路由 (routing) 是指伺服器如何回應客戶端對特定端點 (endpoint) 的請求。端點 (endpoint) 是URI 和特定的 HTTP 請求方法 (GET、POST 等) 組成的。例如,伺服器上提供氣象資訊查詢與回報,則伺服器上的 endpoint 可以有:
    ▪ an endpoint that handles GET/weather /taiwan requests.
    ▪ an endpoint that handles GET / weather/hongkong requests.
    ▪ an endpoint that handles POST / weather / taiwan requests.
    ▪ an endpoint that handles POST/ weather / hongkong requests.


在Express中,製作伺服器端的 routing endpoints 的語法如下:
    1. app.listen (port, callbackFn)

     - app 是個 express instance(object)、port 是我們可以自行決定的數字,callbackFn 是一旦伺服器開始監聽指定的 port,callbackFn 就會被執行。


    2. app.METHOD(PATH, HANDLER) 

    - app 是個 express instance(object)、METHOD 是一個HTTP method,path 是 endpoint,而 handler 是一個 function,一旦伺服器在app.listen() 指定的 port 收到相關 method 與 path 的請求,就會執行 handler function 來回應請求。

    - 當 handler function 被 express 執行時,express 會自動帶入兩個物件當作 parameter,分別為 request object 以及 response object。這兩個物件分別代表 HTTP 的請求以及回應。因此,handler function 通常被寫成 arrow function expression 且此 arrow function 一定會有兩個 parameters:


        (req, res) => {

        // 從 req 拿到資訊

        // 根據拿到的資訊,用 res 做回應

   }

Response Object 常用的 methods 有:

Methods

res.send(body)


res.sendFile(path)

res.json(body)


res.redirect(path)


res.render(view[, locals]) 

res.status()

Description

傳送出 HTTP Respsonse 。 Body 可以是 String, object, array, boolean 

等等。

將位於 path 的文件傳送出去。

發送 JSON response。此 method 會先使用 JSON.stringify() 將 body 轉

換為 JSON String 後,再發送一個 response 給客戶端。

伺服器通過發送狀態為 302 的 HTTP response 要求客戶端到path。客戶

會重新發送一個HTTP GET request 到 path。

將 view 模板套用 locals 的文字後,將 view 發送到客戶端。

設定 HTTP Response 的 status code。

HTTP Status Code

 - HTTP 狀態碼 (Status Code) 是伺服器對任何 HTTP 請求的回應代碼。當我們寄送請求到伺服器後,伺服器會使用一個三位數的代碼表明一個  HTTP 請求是否已經被完成。

 - HTTP Status Code分為五種:
    1. 資訊回應(Informational responses, 100-199)
    2. 成功回應(Successful responses, 200-299)
    3. 重定向(Redirects, 300-399)
    4. 用戶端錯誤(Client errors, 400-499)
    5. 伺服器端錯誤(Server errors, 500-599)

最常見與最常使用的HTTP Status Code:

Code

200 OK

201 Created


302 Found


400 Bad Request

401 Unauthorized

403 Forbidden


404 Not Found

500 Internal Server Error

Meaning

表示請求成功。

請求成功且新的資源成功被創建,通常用於 POST 或一些 PUT 請求後

的回應。

表示請求資源的URI已臨時更改。將來可能會對URI 進行新的更改。因

此,客戶端在以後的請求中應該使用相同的URI。

表示伺服器因為收到無效語法,而無法理解請求。

需要授權以回應請求。它有點像403,但這裡的授權,是有可能辦到的。

用戶端並無訪問權限,例如未被授權,所以伺服器拒絕給予回應。不同於

401,伺服端知道用戶端的身份。

伺服器找不到請求的資源,在網路上它很常出現。

伺服器端發生未知或無法處理的錯誤。

使用範例:(預設的 status code 為 200)

app.get("*", (req, res) => {

  res.status(404).send("你所打的頁面不存在");

  //res.status(404);

  //res.send("你所打的頁面不存在"); 

}); // 當使用者輸入錯誤的網址,會呈現的內容 (需放在所有 rout 最下方)

Request object 常用屬性

req.params

此屬性是一個物件,內部屬性為 named route parameters。例如,如果我們有 route 是 /user/:name,則 “req.params.name” 屬性可取得 route 當中的 name 的值。此物件默認為
{}。

範例:

const express = require("express");

const app = express(); 


app.get("/fruit", (req, res) => {

  res.send("歡迎來到水果頁面");

});

app.get("/fruit/:someFruit", (req, res) => {

  res.send("歡迎來到" + req.params.someFruit + "頁面");

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});


使用者輸入:                     

host/fruit  結果為 ==>  歡迎來到水果頁面

host/fruit/apple  結果為 ==>  歡迎來到apple頁面

host/fruit/banana  結果為 ==>  歡迎來到banana頁面

req.query

此屬性是一個物件,其中包含 route 中 “?” 後面的 key-value pair。例如,如果我們有 route 是 /api/getUser/?id=1,則 req.query.id 就會是 1。

範例:在工作目錄裏面有 2 個檔案

1. example.html - 裡面有一個 form

2. app.js

example.html

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <form action="/formhandling" method="GET">

      <label for="name">名稱</label>

      <input type="text" id="name" name="name" />

      <label for="age">年齡:</label>

      <input type="number" name="age" />

      <button>交出表單</button>

    </form>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 

app.get("/example", (req, res) => {

  res.sendFile(__dirname + "/example.html");

}); 

app.get("/formhandling", (req, res) => {

  res.send(

    "伺服器已經收到表單。你所提交的資料為,名稱:" +

      req.query.name +

      ",以及年齡為" +

      req.query.age

  );

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/example,輸入名稱 David、年齡 23,之後按下交出表單按鈕。

3. 結果會跳轉至儲存頁面:http://localhost:3000/formhandling?name=David&age=23

    伺服器已經收到表單。你所提交的資料為,名稱:David,以及年齡為23

req.body

此屬性是一個物件,預設值是 undefined,但若使用 express.json() 或是 express.urlencode()這種 middleware,可以讓內部包含 POST request 寄來的資料訊息,用 key-value pair 來表示

express.json() 會去檢查 requests 的 header 有沒有 Content-Type: application/json。如果有,就把 text-based JSON 換成 JavaScript 能夠存取的 JSON 物件。

express.urlencoded() 會去檢查 requests 的 header 有沒有 Content-Type:
application/x-www-form-urlencoded (也就是去檢查是不是帶有資料的 POST
request)。如果有,也把 text-based JSON 換成 JavaScript 能夠存取的 JSON 物件。Extended 屬性設定為 true,可以讓 JSON 物件內部儲存 String 以外的資料類型。

總合來說,express.json() 以及 express.urlencoded() 功能一樣,只是處理的 Content-Type 不同。兩者轉換完成的 JSON 物件會被放入 req.body。

範例 1:在工作目錄裏面有 2 個檔案

1. example.html - 裡面有一個 form

2. app.js

example.html

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <form action="/formhandling" method="POST">

     

<label for="email">Email</label>

      <input type="email" name="email" />

      <label for="password">Password</label>

      <input type="password" name="password" />

      <button>交出表單</button>

    </form>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 


// middlewares - express 的 built-in function

app.use(express.json());

app.use(express.urlencoded({ extended: true }));


app.get("/example", (req, res) => {

  res.sendFile(__dirname + "/example.html");

}); 


app.post("/formhandling", (req, res) => {

  let { email, password } = req.body;

  res.send("你的信箱是" + email);

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/example,輸入email:xxxxx@outlook.com、password:*******,之後按下交出表單按鈕。

3. 結果會跳轉至儲存頁面:http://localhost:3000/formhandling

    你的信箱是xxxxx@outlook.com

Express Middleware (中介軟體)

 - Middleware (中介軟體) 是指從發出 HTTP 請求後,到伺服器回覆回應前,用來做特定用途的程式。每個 Middleware 可以針對所收到的物件進行修改或解析,處理後再來決定是否要繼續把物件繼續傳遞給下一個 middleware。

 - 在 Express.js 中,最基礎的使用 middleware 的語法是:

app.use(callbackFn)

 - 不論是 GET request,POST request 還是其他種類的 request methods,app.use() 內部的callbackFn 都會被 Express.js 執行。

 - callbackFn 被 Express.js 執行時,會使用基本的三個參數:req, res, next。next 本身是個function

 - 如果目前的 middleware 不打算結束客戶端的請求、也沒有傳遞回應給客戶端,就必須呼叫 next() 以便將控制權傳遞給下一個 middleware。否則,若是目前的 middleware 既沒有執行next(),也沒有給客戶端回應,則客戶端的 request 將會停擺。

*. 錯誤處理中介軟體 (error-handling middleware )是專門用來處理錯誤狀況所使用的。撰寫錯誤處理中介軟體時, callbackFn 則會使用四個參數,分別為為 err、req、res 與 next。 err參數代表:當錯誤發生時,Express.js 會把 error object 當作 argument 放入 callbackFn 內部。

範例 2:在工作目錄裏面有 2 個檔案

1. example.html - 裡面有一個 form

2. app.js

example.html

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <form action="/formhandling" method="POST">

     

<label for="email">Email</label>

      <input type="email" name="email" />

      <label for="password">Password</label>

      <input type="password" name="password" />

      <button>交出表單</button>

    </form>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 


// middlewares

app.use((req, res, next) => {

  console.log("正在經過middleware...");

  next(); // 如果沒寫 next(),客戶端的 request 將會停擺

});

app.use((req, res, next) => {

  console.log("正在經過第二個middleware...");

  next(); // 如果沒寫 next(),客戶端的 request 將會停擺

});


app.get("/example", (req, res) => {

  res.sendFile(__dirname + "/example.html");

}); 


app.post("/formhandling", (req, res) => {

  let { email, password } = req.body;

  res.send("你的信箱是" + email);

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/,城市內部會先跑過此兩個 middleware 之後再回應 http://localhost:3000/ 的 request。

除了自己寫出 app.use() 內部的 callbackFn之外,我們也可以使用 Express 的 built-in function,放入 app.use() 內部,例如::

    app.use(express.static('public'));

    app.use(express.json()); //範例一

    app.use(express.urlencoded({extended: true})); //範例一

Static Files

 - 靜態文件 (static files) 是客戶端可以從伺服器下載的文件。例如:404錯誤訊息網頁、CSS文件、網頁中的圖片、JavaScript 文件等等,都是網頁伺服器不需要通過腳本語言去組成的網頁,而是可以直接寄送給客戶端的文件。

- 在 Express.js 當中,預設的情況下是不允許我們提供 Static Files。 我們需要先使用middleware:

app.use(express.static('public'));

才能向客戶端提供static files。

 - 我們需要在 work directory 當中創建一個資料夾,名稱必須是 “public”。所有的 static files都可以放進 public 資料夾內部。

注意!! 當 Express 查找 public 資料夾內部的文件時,使用的是相對路徑,且 public 資料夾名稱不是 URL 的一部份。

範例 2:

1. index.html

2. public 資料夾,裡面有一個 style.css

3. app.js

index.html

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

    <link rel="stylesheet" href="/style.css" />

  </head>

  <body>

    <h1>歡迎來到首頁</h1>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 


// middlewares

app.use(express.static("public"));


app.get("/", (req, res) => {

  res.sendFile(__dirname + "/index.html");

}); 


// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/,網頁呈現黑底白字。(表示:style.css 需放入 public 資料夾裡面)

Embedded JavaScript (EJS)

 -EJS 的全名是「Embedded JavaScript,是與 Express.js 搭配的內嵌式的樣板引擎。 EJS 可以讓我們使用 JavaScript 生成 HTML 頁面 (在 HTML 裡面使用 JavaScript)。 EJS文件需要放在「views」資料夾內部

 - 頁面渲染 (rendering) 就是瀏覽器將 HTML 變成人眼看到的圖像的全過程。Express.js 當中的 View Engine 允許我們使用模板文件 (HTML) 渲染網頁。這些模板填充了實際數據並從伺服器被傳送到客戶端。

 - 若有使用 app.set(“view engine”, “ejs”),則使用 res.render() 時,就不需要指定文件類別。例如:res.render("index.ejs”) 可以改成 res.render(“index”)。

EJS install:(work directory)

    npm install ejs

EJS

範例 :


1. 在 work directory 新增一個 views資料夾,裡面有一個 index.ejs

2. app.js

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <h1>這是一個EJS製作出的頁面

</h1>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 


// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");

app.get("/", (req, res) => {

  res.render("index");

}); 


// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/,網頁呈現黑底白字。(表示:style.css 需放入 public 資料夾裡面)

res.render(view[, locals])

- 將 view 模板套用 locals 的文字後,將 view 發送到客戶端。

範例 :(模板套用)


1. 在 work directory 有 views資料夾,裡面有一個 index.ejs

2. app.js

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <h1>這是一個<%= name %>製作出的頁面

</h1>

  </body>

</html>

app.js

const express = require("express");

const app = express(); 


// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");

app.get("/:name", (req, res) => {

  let {name} = req.params;

  res.render("index", {name});

});


// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/Grace,網頁呈現:

這是一個Grace製作出的頁面

   進入 http://localhost:3000/Mike,網頁呈現:

這是一個Mike製作出的頁面

EJS 語法

<% 一般標籤,用於control flow,不輸出任何的值。


<%= 將值輸出到模板中 (不會轉換HTML語法)。例如:x=“<p>This is a paragraph</p>",則<%=x%>會是輸出<p> This is a paragraph</p>。

範例 1:

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <%for (let i = 0; i < 10; i++) {%> 

    <%=i%>

    <%}%> 

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  res.render("index");

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

範例 2:

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <%for (let i = 0; i < 10; i++) {%> 

    <h1><%=i%></h1>

    <%}%> 

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  res.render("index");

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});


<%- 將轉換過的 HTML 語法的值輸出到模板中。例如:x="<p>This is a paragraph</p>",則 <%-x%> 會是輸出 This is a paragraph。

範例 :

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <%for (let i = 0; i < 10; i++) {%> 

    <%- mystring %>

    <%}%> 

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  let mystring = "<h1>hello world</h1>";

  res.render("index", { mystring });

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});


<%# 注釋標籤,不執行也不輸出任何的值。


%> 普通的結束標籤。


<%- include %> 語法可以鑲嵌其他 EJS 文件。

範例 :鑲嵌其他 EJS 文件

在 views 資料夾中,新增一個 partials 資料夾(也可不用新增),裡面有一個 footer.ejs 檔案:

<h2>這是一個 footer...</h2>

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <%for (let i = 0; i < 10; i++) {%> 

    <%- mystring %>

    <%}%> 

   <%-

    include("partials/footer") %>

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  let mystring = "<h1>hello world</h1>";

  res.render("index", { mystring });

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

EJS 應用示範

範例 1 :使用者在表格中輸入資料之後,跳轉至已接收畫面。

在 views 資料夾中,新增 response.ejs 檔案。

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

  <form action="/example" method="GET">

      <label for="name">名稱:</label>

      <input type="text" id="name" name="name" />

      <label for="age">年齡:</label>

      <input type="number" id="age" name="age" />

      <button>交出表單</button>

    </form>

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  res.render("index");

});

app.get("/example", (req, res) => {

  let { name, age } = req.query;

  res.render("response", { name, age });

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

response.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <h1>恭喜!資料已經送到伺服器端了</h1>

    <h3>以下是您提供的資料:</h3>

    <p>您的姓名是<%= name %></p>

    <p>您的年齡是<%= age %></p>

  </body>

</html>

執行:

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/,輸入名稱:Stan 、年齡:28,點擊 "交出表單" 按鈕。

EJS example1

3. 接著會跳轉至:http://localhost:3000/example?name=Stan&age=28

EJS example2

範例 2 :將已有的資料 (array),利用 forEach() 製作出表格。

index.ejs

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

  <table>

      <tr>

        <th>名稱</th>

        <th>評價</th>

        <th>熱門程度</th>

        <th>流行度</th>

      </tr>

      <% languages.forEach(lang => {%>

      <tr>

        <td><%= lang.name%></td>

        <td><%= lang.rating%></td>

        <td><%= lang.popularity%></td>

        <td><%= lang.trending%></td>

      </tr>

      <%})%>

    </table>

  </body>

</html>

app.js

const express = require("express");

const app = express(); // 物件 (代表伺服器)

// middlewares

app.use(express.static("public"));

app.set("view engine", "ejs");


app.get("/", (req, res) => {

  const languages = [

    { name: "Python", rating: 9.5, popularity: 9.7, trending: "super hot" },

    { name: "Java", rating: 9.4, popularity: 8.5, trending: "hot" },

    { name: "C++", rating: 9.2, popularity: 7.7, trending: "hot" },

    { name: "PHP", rating: 9.0, popularity: 5.7, trending: "decreasing" },

    { name: "JS", rating: 8.5, popularity: 8.7, trending: "hot" },

  ];

  res.render("index", { languages });

});

// parameters: port, callback

app.listen(3000, () => {

  console.log("伺服器政在聆聽 port 3000...");

});

執行:

1. 在 terminal 執行 nodemon app.js

2. 進入 http://localhost:3000/:(製作出表格)

EJS example3
{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>