2. Express 使用指南

1、什麼是Express?

www.expressjs.com.cn/javascript

基於 Node.js 平臺,快速、開放、極簡的 Web 開發框架。提供了一系列強大特性幫助你建立各類Web 應用,和豐富的 HTTP 工具。使用 Express 能夠快速地搭建一個完整功能的網站。html

Express 框架核心特性:前端

  • 能夠設置中間件來響應HTTP 請求。java

  • 定義了路由表用於執行不一樣的HTTP 請求動做。node

  • 能夠經過向模板傳遞參數來動態渲染HTML 頁面。mysql

2、安裝

經過npm安裝:sql

$ npm i -S express
複製代碼

安裝完成後,咱們可經過以下指令查看express版本號:shell

$ npm list express
└── express@4.17.1 
複製代碼

如下模塊是須要與express 框架一塊兒安裝的:數據庫

  • body-parser : nodeJS中間件,用於處理 JSON, Raw, Text 和 URL 編碼的數據。express

  • cookie-parser :解析Cookie的工具 。經過req.cookies能夠取到傳過來的cookie,並把它們轉成對象。

  • multer:nodeJS中間件,用於處理 enctype="multipart/form-data"(設置表單的MIME編碼)的表單數據。

$ npm i -S body-parser cookie-parser multer
複製代碼

3、構建服務器

在項目根目錄建立app.js文件

// 1. 導入express
const express = require("express");
// 2. 建立express實例
const app = express();
// 3. 監聽 http://127.0.0.1:8081
app.listen(8081, "127.0.0.1");
// 4. 監聽GET請求,用戶訪問路徑 /
app.get("/", (req, res) => {
    // req -> request -> 請求對象
    // res -> response -> 響應對象
  	// 響應,向前端發送數據
    res.send("Hello, express!");
});
// 5. 打印輸出提示信息
console.log("server running at http://127.0.0.1:8081");
複製代碼

終端執行腳本,運行app.js

$ node app.js
複製代碼

在瀏覽器輸入:http://127.0.0.1:8081,可看到頁面輸出「Hello, express!」

注意:listen 方法中的ip地址設置的是哪些ip能訪問該服務器,而不是服務器地址,若是容許局域網內的全部設備訪問該服務器,在設置 listen 方法的 ip 參數時能夠設置爲 」0.0.0.0「,這樣,局域網內的其餘設備就能夠經過服務器所在電腦的 」ip地址:端口號「 訪問啦。

4、處理跨域

1. 容許全部域名跨域

app.all("*", (req, res, next) => {
    // 設置容許跨域的域名,*表明容許任意域名跨域
    res.header("Access-Control-Allow-Origin","*");
    // 容許的header類型
    res.header("Access-Control-Allow-Headers","content-type");
    // 跨域容許的請求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  // 讓options嘗試請求快速結束
    else
        next();
});
複製代碼

2. 容許指定域名跨域

假定容許 「http://127.0.0.1:5500」 訪問:

app.all("*", (req, res, next) => {
    // 設置容許跨域的域名,*表明容許任意域名跨域
    res.header("Access-Control-Allow-Origin","http://127.0.0.1:5500");
    // 容許的header類型
    res.header("Access-Control-Allow-Headers","content-type");
    // 跨域容許的請求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  //讓options嘗試請求快速結束
    else
        next();
});
複製代碼

3. 容許多個域名跨域

app.all("*", (req,res,next) => {
    //定義容許跨域的域名集合
    const origin_list = [
        "http://127.0.0.1:5500",
        "http://127.0.0.1:5501",
        "http://127.0.0.1:5502"
    ];
    if(origin_list.includes(req.headers.origin.toLowerCase())) {
        // 設置容許跨域的域名,*表明容許任意域名跨域
        res.header("Access-Control-Allow-Origin", req.headers.origin);
    }
    // 容許的header類型
    res.header("Access-Control-Allow-Headers","content-type");
    // 跨域容許的請求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  // 讓options嘗試請求快速結束
    else
        next();
});
複製代碼

5、路由

1. 基本操做

路由是指如何定義應用的端點(URIs)以及如何響應客戶端的請求。路由是一個由URI、HTTP請求(GET/POST等)和若干個句柄組成,它的語法結構以下:

app.method(path:string, hander:function) 複製代碼

語法解讀:

  • app:express對象的一個實例
  • method:http請求方法(get/post),小寫
  • path:路徑,接口地址 = 服務器地址 + path
  • hande:當路由匹配時要執行的處理函數
// GET請求
// http://127.0.0.1:8081/
app.get("/", (req, res) => {
    console.log("有人經過GET訪問:/");
}); 
app.get("/register", (req, res)=>{

})
// POST請求
// http://127.0.0.1:8081/login
app.post("/login", (req, res)  => {
    console.log("有人經過POST訪問:/login");
});        
複製代碼

2. 模塊化配置

將路由定義在app.js文件中,不利於閱讀維護,特別是在項目比較大的狀況下,因此咱們須要將路由模塊化。好比項目有用戶、和商品功能,那咱們就定義2個路由,文件結構以下:

|- proj
   |- routes
  	  |- user.js
  	  |- order.js
|- app.js	
複製代碼

路由分析:

- 用戶接口 user
> 登陸接口:POST /login
參數1 => username:string required
參數2 => password:string required

> 註冊接口:POST /register
參數1 => username:string required
參數2 => password:string required
參數3 => tel: string options


- 訂單接口 order
> 增 POST /order/add
> 刪 GET  /order/delete
> 查 GET  /order/query
> 改 POST /order/modify
複製代碼

user.js

// 1. 建立路由實例
const router = require("express").Router();
// 2. 配置路由
router.post("/login", (req, res) => {
    console.log("「登陸接口」被調用");
});
router.post("/register", (req, res) => {
    console.log("「註冊接口」被調用");
});
// 3. 導出路由
module.exports = router;
複製代碼

order.js

// 1. 建立路由實例
const router = require("express").Router();
// 2. 配置路由
router.get("/", (req, res) => {
    console.log("「查詢訂單接口」被調用");
});
router.post("/add", (req, res) => {
    console.log("「添加訂單接口」被調用");
});
router.post("/delete", (req, res) => {
    console.log("「刪除訂單接口」被調用");
});
router.post("/modify", (req, res) => {
    console.log("「修改訂單接口」被調用");
});
// 3. 導出路由
module.exports = router;
複製代碼

app.js

// 1. 導入express
const express = require("express")();
// 2. 獲取express實例
const app = express();
// 3. 處理跨域
app.all("*", (req, res, next) => {
    // 設置容許跨域的域名,*表明容許任意域名跨域 CROS
    res.header("Access-Control-Allow-Origin","*");
    // 容許的header類型
    res.header("Access-Control-Allow-Headers","content-type");
    // 跨域容許的請求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  // 讓options嘗試請求快速結束
    else
        next();
});
// 4. 處理路由
const userRouter  = require("./routes/user");
const orderRouter = require("./routes/order");
app.use("/", userRouter);
app.use("/orders", orderRouter);

// 5. 監聽 http://127.0.0.1:8081
app.listen(8081, "0.0.0.0");
// 6. 打印輸出提示信息
console.log("server running at http://127.0.0.1:8081");
複製代碼

6、參數

2.1. GET

經過 req.query 便可獲取GET請求參數,並且最終獲取的仍是已經被轉換爲對象了的參數,在原生nodeJS實現中,咱們還須要使用 queryString 模塊來進行顯式的轉換。

2.2. POST

這裏須要使用咱們剛纔安裝的 body-parser 模塊,獲取POST參數,需注意如下幾點:

  • 前端代碼須要傳遞請求頭,請求參數需以JSON字符串形式傳遞。

  • 後端代碼須要添加中間件 body-parser牢記

  • 通過中間件的處理,參數會自動的添加到req請求對象上,做爲其一個屬性body

前端代碼:

fetch("http://127.0.0.1:8081/login", {
    method: "post",
    body: JSON.stringify({
        username: "admin",
        password: "123"
    }),
    headers: {
        "Accept": "application/json",
        "Content-Type": "application/json"
    }
})
.then(res => res.json())
.then(res => {
    console.log(res);
});
複製代碼

後端代碼:

// 4. 中間件
const bodyParser = require("body-parser");
// application/x-www-form-urlencoded 解析
app.use(bodyParser.urlencoded({extended:false}));
// application/json 解析
app.use(bodyParser.json());
// 5. 路由配置
app.post("/login", (req, res) => {
    // 打印參數
    console.log(req.body);
    // 響應數據
    res.send({
        nikename: "木子李",
        tel: "152-2888-5771",
        address: "成都市高新區雅和南四路216號"
    });
});
複製代碼

關於body-parser中間件詳細內容可參考以下文章:

www.jianshu.com/p/ea0122ad1…

7、請求與響應

  • request:HTTP請求對象,包含了請求查詢字符串,參數,內容,HTTP 頭部等屬性
  • response:HTTP 響應對象,即在接收到請求時向客戶端發送的 HTTP 響應數據

在Express中,請求對象與響應對象做爲路由處理函數的參數返回,以下所示:

app.get("/", (req, res) => {
   req.body  // => 讀取post參數
   req.query // => 讀取get參數
   res.send  // => 響應客戶端
});
複製代碼

關於req、res經常使用屬性和方法,點擊上述連接進入API文檔查看。

8、靜態資源訪問

經過Express 提供的內置中間件 express.static ,咱們能夠實現訪問靜態資源(如圖片、CSS、JavaScript等)的需求。例如,若是將圖片、CSS、JavaScript 文件放在 www 目錄下,你能夠這麼寫:

app.use(express.static("www"));
複製代碼

那咱們便可在瀏覽器中經過」http://127.0.0.1:8081/images/logo.png「訪問靜態資源了。

服務器端靜態資源的文件結構以下:

|- proj
	 └── routes
	 └── app.js
	 └── www
  	 		└── images
  	 		└── javascripts 		
  	 		└── stylesheets
複製代碼

總結:

\1. 在最開始處使用express內置的static中間件,來實現靜態文件的訪問。

\2. 前端訪問時,地址欄只需輸入服務器地址 + express.static 參數內的路徑和文件名稱便可。

9、連接數據庫

1. 流程

a)、安裝mysql模塊

$ npm i -S mysql
複製代碼

b)、導入mysql模塊

const mysql = require("mysql");
複製代碼

c)、連接數據庫

const connection = mysql.createConnection({
    // 主機名
    host: '127.0.0.1',
    // 端口
    port: '3306',
    // 用戶名
    user: 'root',
    // 密碼
    password: '1234',
    // 數據庫名
    database: 'db_test'
});
connection.connect(); // 啓動鏈接
// 數據庫操做...
connection.end(); // 關閉鏈接
複製代碼

更多參數參考:www.npmjs.com/package/mys…

2. 操做

在鏈接數據庫的狀況下咱們開始操做數據庫連接對象:connection。

mysql 數據庫heros表中的字段信息:

mysql 數據庫heros表中的數據信息:

2.1. 查詢數據庫信息

-> 語法形式:

connection.query(sql,function (err, sqlRes) {});
複製代碼

-> 參數解讀:

  • sql:操做數據庫的指令(sql語句)
  • function(){}:返回查詢結果的回調函數

-> 代碼示例:

connection.connect();
const sql = "SELECT * FROM heros";
function fn(err, sqlRes) {
    if(err) {
        console.log(err.message);
    }else {
        console.log(sqlRes);
    }
}
connection.query(sql, fn)
connection.end();  // 操做完數據庫記得關閉連接
複製代碼

-> 注意事項:

1)若是你想經過定時器來循環操做數據庫,那麼數據庫的開啓連接語句必定要放在這些語句以外。

2)關閉連接語句要寫的話也應該寫在定時執行的函數裏面,否則定時器執行一次,連接就會關掉,就沒法在操做數據庫了。

3)關閉連接後,獲取數據庫連接對象只能從新執行*mysql.createConnection()*方法。

4)不能屢次重複調用 .connect() 方法,不然會報錯。

5)不能屢次重複調用 .end() 方法,不然會報錯。

-> 查詢結果:

-> 遍歷結果:

實際上查詢出的結果是一個對象數組,咱們能夠經過下標與鍵取出其中詳細數據,也能經過循環將其全部值遍歷出來

-> 1. 單獨取值:

reqRes.[0];
reqRes.[0].name;
複製代碼

-> 2. 遍歷取值

for(let i = 0, len = reqRes.length; i < len; i++) {
    console.log(reqRes[i]);
}
複製代碼

-> 3. 將查詢結果返回給前端

能夠看到,都不須要作什麼處理,直接把查詢結果用 JSON.parse(sqlRes) 轉換爲字符串就能夠發到前端了,前端在轉換爲對象數組就能直接用了

-> 4. 條件查詢

-> 5. 預編譯寫法

其實這裏能夠寫成預編譯的方式,能夠避免sql注入的問題,所謂預編譯就是說對於本來在sql裏面寫值換成佔位,而後傳入一個數組進去補全這個佔位符,也就是connect.query 方法會多一個參數,爲一個數組,放入第二個位置。

2.2. 修改數據庫信息

-> 語法形式:

connection.query(sql, sqlParams, function (err, sqlRes) {});
複製代碼

-> 參數解讀:

  • sql:sql指令,如:UPDATE heros SET location=? WHERE name=?
  • sqlParams:sql參數,如:["上路", "周瑜"]
  • function(){}:執行結果回調函數

-> 代碼示例:

提示:咱們可經過影響行數 affectedRows 屬性判斷是否修改爲功。

2.3. 添加數據信息

-> 語法形式:

connection.query(sql, sqlParams, function (err, sqlRes) {});
複製代碼

-> 參數解讀:

  • sql:sql指令,如:INSERT INTO heros (name, skill) VALUES (?, ?)
  • sqlParams:sql參數,如:["貂蟬", "綻·風華"]
  • function(){}:執行結果回調函數

-> 代碼示例:

2.4. 刪除數據信息

-> 語法形式:

connection.query(sql, sqlParams, function (err, sqlRes) {});
複製代碼

-> 參數解讀:

  • sql:sql指令,如:DELETE FROM heros WHERE name=?
  • sqlParams:sql參數,如:["貂蟬"]
  • function(){}:執行結果回調函數

-> 代碼示例:

3. 連接數據庫封裝

3.1. 概述

在上面咱們每次操做數據庫都要先鏈接下數據庫,而後才能操做,那麼咱們是否可以把數據的連接封裝起來呢,這樣每次直接獲取連接對象,來操做數據庫便可,會方便很多。

3.2. 示例

const mysql = require("mysql");
const defaultOptions = {
    host: '127.0.0.1',
    port: '3306',
    user: 'root',
    password: '1234',
    database: 'db_test'
}
function getConnection(options = defaultOptions) {
    return mysql.createConnection(options);
}
module.exports = getConnection;
複製代碼

使用

const getConnection = require("./mysqlConnection");
const db = getConnection();
app.get("/heros", (req, res) => {
    db.connect();
    const sql = "SELECT * FROM heros";
    function fn(err, sqlRes) {
        if(err) {
            console.log(err.message);
        }else {
            res.end(JSON.stringify(sqlRes));
        }
    }
    db.query(sql, fn)
    db.end();
});
複製代碼

4. 異常

  1. 連接數據庫時報錯:client does not support authentication protocol requested by server consider
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '本身的密碼';
複製代碼
相關文章
相關標籤/搜索