Express這些中間件還沒掌握的話趕緊學習起來啦!【持續更新中】

1、導讀

學了Express框架有一段時間了,感覺Express本身就是一個極其簡單的框架。一個完整的web開發框架其實都是由各種路由還有大量的中間件構成的,從本質上來說,一個Express的應用其實就是在調用各種中間件。

所以,掌握好一些常用的中間件我覺得是很有必要的,這可以很好的提高你的開發效率。因此寫下這篇文章,文章主要會從Express自身的一些中間件再到一些第三方的中間進行講解。首先讓我們來了解下什麼是中間件?

2、什麼是中間件

中間件就是一堆方法,可以接收客戶端發來的請求、可以對請求做出響應,也可以將請求繼續交給下一個中間件繼續處理。

2.1中間件的構成

中間件主要由兩部分構成,中間件方法以及請求處理函數。
中間件方法由Express提供,負責攔截請求,請求處理函數由開發人員提供,負責處理請求。

app.get('請求路徑', '處理函數')   // 接收並處理get請求
app.post('請求路徑', '處理函數')  // 接收並處理post請求

2.2中間件的處理方式

我們可以針對同一個請求設置多箇中間件,對同一個請求進行多次處理。
默認情況下,請求會從上到下依次匹配中間件,一旦匹配成功,終止匹配。
可以調用next方法將請求的控制權交給下一個中間件,直到遇到結束請求的中間件。
注意:

1.如果在post,get請求過程中的回調函數沒有next()參數,那麼就會匹配上第一個路由,而不會往下匹配了。如果想往下匹配的話,處理函數的參數中就需要寫next,在處理函數中調用next().
2.如果當前中間件函數沒有結束請求/響應循環,那麼它必須調用 next(),以將控制權傳遞給下一個中間件函數。否則,請求將保持掛起狀態。

app.get('/request', (req, res, next) => {
     req.name = "張三";
     next();
 });
 app.get('/request', (req, res) => {
     res.send(req.name);
 });

3.應用層級中間件

3.1app.METHOD()

使用 app.use() 和 app.METHOD() 函數將應用層中間件綁定到應用程序對象的實例,其中 METHOD 是中間件函數處理的請求的小寫 HTTP 方法(例如 GET、PUT 或 POST)。

app.get('/request', (req, res) => {
     req.name = "張三";
 });

3.2 app.use()

app.use 匹配所有的請求方式(GET,PUT,POST…),可以直接傳入請求處理函數,代表接收所有的請求。

app.use((req, res, next) => {
     console.log(req.url);
     next();
 });

app.use 第一個參數也可以傳入請求地址,代表不論什麼請求方式,只要是這個請求地址就接收這個請求。

 app.use('/admin', (req, res, next) => {
     console.log(req.url);
     next();
 });

4.路由器層中間件

路由器層中間件的工作方式與應用層中間件基本相同,差異之處在於它綁定到 express.Router() 的實例。他的好處在於對路由處理進行解耦
index.js

const express = require('express')
const userRouter = require('./user')
const router = express.Router()
router.use('/user', userRouter)

user.js

const express = require('express')
const router = express.Router()
router.post('/login', function(req, res) {}
module.exports = router

然後當我們想使用user.js下面/login路由的話,我們就必須得通過 /user/login路由進行訪問,直接/login是訪問不到的。這也對路由也有了一個層級的關係。

5.錯誤處理中間件

在程序執行的過程中,會不可避免的會出現一些無法預料的錯誤,比如文件讀取失敗,數據庫連接失敗。而錯誤處理中間件是一個集中處理錯誤的地方。
注意:

錯誤處理中間件始終採用四個自變量。必須提供四個自變量,以將函數標識爲錯誤處理中間件函數。即使無需使用 next 對象,也必須指定該對象以保持特徵符的有效性。否則,next 對象將被解釋爲常規中間件,從而無法處理錯誤。

 app.use((err, req, res, next) => {
     res.status(500).send('服務器發生未知錯誤');
 })

當我們在前面的中間件遇到錯誤的時候,我們可以通過調用next()方法將錯誤信息通過參數的形式傳遞給next()方法,即可觸發錯誤處理中間件。

 app.get("/", (req, res, next) => {
     fs.readFile("/file.txt", (err, data) => {
         if (err) {
            next(err);
         }
     });
});

6.內置中間件

Express 中唯一內置的中間件函數是 express.static(root, [options])。它負責提供 Express 應用程序的靜態資源,例如img、CSS、JavaScript 文件等。
root 自變量指定從其中提供靜態資源的根目錄。而對於每個應用程序,可以有多個靜態目錄

app.use('/static',express.static('public'));
app.use('/aaa',express.static('imges'));

表示現在 你就可以通過帶有“/static ”前綴的地址來訪問public目錄下面的文件了
比如我們可以通過以下進行訪問:

  • http://localhost:3000/static/abc.jpg
  • http://localhost:3000/aaa/bcd.jpg

7.第三方中間件

post請求解析

相關地址:https://github.com/expressjs/body-parser/
https://www.cnblogs.com/chyingp/p/nodejs-learning-express-body-parser.html
body-parser是一個HTTP請求體解析的中間件,使用這個模塊可以解析JSON、Raw、文本、URL-encoded格式的請求體,是經常使用的一箇中間件。
基本使用方法:

  1. 安裝
npm i -S body-parser
  1. 使用
const bodyParser = require('body-parser')

// 創建 express 應用
const app = express()
//對body-parser進行配置
// 使node後臺支持了application/x-www-form-urlencoded請求體
app.use(bodyParser.urlencoded({ extended: true //擴展模式 }))
// 使node後臺支持了application/json請求體
app.use(bodyParser.json())

設置完畢之後,會在req對象上面新增一個req.body的一個對象,我們就可以通過直接使用req.body.屬性名 獲取到對應到值了。

跨域中間件 cors

當你遇到了跨域的問題,最簡單的解決辦法就是安裝一個cors中間件了。這樣就不會遇到跨域問題~
相關地址:https://github.com/expressjs/cors
基本使用方法:

  1. 安裝
npm i -S cors
  1. 使用
const cors = require('cors')

app.use(cors())

上面的使用方法說明了所有網站都可以進行訪問,當然我們可以執行只有某些網站纔可以進行訪問。

var corsOptions = {
  origin: 'http://www.baidu.com', //只有百度可以訪問
  optionsSuccessStatus: 200 
}

app.get('/products/:id', cors(corsOptions), function (req, res, next) {
  res.json({msg: '只有百度可以訪問'})
})

mysql數據庫查詢

相關地址:https://github.com/mysqljs/mysql
基本使用方法:

  1. 安裝mysql庫
npm i -S mysql
  1. 配置
    創建 db 目錄,新建兩個文件: index.js,config.js
    config.js 源碼如下:
module.exports = {
  host: 'localhost',
  user: 'root',
  password: '12345678',
  database: 'book'
}
  1. 連接
    連接數據庫需要提供使用 mysql 庫的 createConnection 方法,在 index.js 中創建如下方法:
function connect() {
  return mysql.createConnection({
    host,
    user,
    password,
    database,
    multipleStatements: true
  })
}

multipleStatements:允許每條 mysql 語句有多條查詢.使用它時要非常注意,因爲它很容易引起 sql 注入(默認:false)

  1. 查詢(查詢需要調用 connection 對象的 query 方法)
function querySql(sql) {
  const conn = connect()
  return new Promise((resolve, reject) => {
    try {
      conn.query(sql, (err, results) => {
        if (err) {
          reject(err)
        } else {
          resolve(results)
        }
      })
    } catch (e) {
      reject(e)
    } finally {
      conn.end()
    }
  })
}

conn 對象使用完畢後需要調用 end 進行關閉,否則會導致內存泄露

5.調用方法

db.querySql('select * from book').then(result => {
  console.log(result)
})

MD5加密 crypto

相關地址:http://nodejs.cn/api/crypto.html
基本使用方法:

  1. 安裝 crypto 庫:
npm i -S crypto
  1. 創建 md5 方法:
const crypto = require('crypto')

function md5(s) {
  // 注意參數需要爲 String 類型,否則會出錯
  return crypto.createHash('md5')
    .update(String(s)).digest('hex');
}

看別人說MD5加密好像可以破解,採用MD5+Salt加密可以更加安全。

express-validator 表單驗證

express-validator 是一個功能強大的表單驗證器,它是 validator.js 的中間件。
它驗證請求的body, params, query, headers 和 cookies ,並且如果任何配置的驗證規則失敗,返回一個錯誤的響應;
相關地址:https://github.com/express-validator/express-validator
https://www.kutu66.com//GitHub/article_76137
基本使用方法:

  1. 安裝
npm install express-validator
  1. 驗證
    在請求當中的第二個參數添加一個數組,數組爲校驗規則,然後使用body方法進行校驗。
const { body, validationResult } = require('express-validator')
const boom = require('boom')

router.post(
  '/login',
  [
  	//  body 方法判斷參數類型是否爲字符串,並指定出錯時的提示信息
    body('username').isString().withMessage('username類型不正確'),
    body('password').isString().withMessage('password類型不正確')
  ],
  function(req, res, next) {
  	//使用 const err = validationResult(req) 獲取錯誤信息,err.errors 是一個數組,包含所有錯誤信息,如果 err.errors 爲空則表示校驗成功,沒有參數錯誤
    const err = validationResult(req)
    // 判斷是否有錯誤
    if (!err.isEmpty()) {
      //存在錯誤。msg爲錯誤消息,然後這裏將其穿個下個錯誤中間件處理。
      // const msg = err.error
      const [{ msg }] = err.errors   // 數組加對象的雙重解構
      next(boom.badRequest(msg))
    } else {
      const username = req.body.username
      const password = md5(`${req.body.password}${PWD_SALT}`)

      login(username, password).then(user => {
        if (!user || user.length === 0) {
          new Result('登錄失敗').fail(res)
        } else {
          new Result('登錄成功').success(res)
        }
      })
    }
  })

JWT 解析 express-jwt

有使用JWT的認證,當然也需要JWT的解析啦,關於JWT的使用可以看我另外一篇文章:
Node 生成 JWT Token的使用方法
相關地址:https://github.com/auth0/express-jwt
基本使用方法:

  1. 安裝
npm i -S express-jwt
  1. 可以選擇創建一個用於JWT解析的文件
// 用於驗證指定http請求的JsonWebTokens的有效性
const expressJwt = require('express-jwt')
const { PRIVATE_KEY } = require('../utils/constant')

const jwtAuth = expressJwt({
  secret: PRIVATE_KEY, //  簽名的密鑰 或 PublicKey
  credentialsRequired: true, // 設置爲false就不進行校驗了,遊客也可以訪問
}).unless({
  path: [
    '/',
    '/user/login',
    //jwt的白名單,在該名單內說明不會進行校驗
  ],
})

module.exports = jwtAuth
  1. 在需要用到的地方使用該中間件
const jwtAuth = require('./jwt')

// 註冊路由
const router = express.Router()

// 對所有路由進行 jwt 認證
router.use(jwtAuth)

文件上傳 multer

multer 用於處理 multipart/form-data 類型的表單數據,它主要用於上傳文件。
相關鏈接:https://github.com/expressjs/multer

基本使用方法:

  1. 安裝
npm install -S multer 
  1. 使用
    Multer在解析完請求體後,會向Request對象中添加一個body對象和一個file或files對象(上傳多個文件時使用files對象 )。其中,body對象中包含所提交表單中的文本字段(如果有),而file(或files)對象中包含通過表單上傳的文件。
const express = require('express')
const { UPLOAD_PATH } = require('../utils/constant')
// 文件上傳
const multer = require('multer')
const router = express.Router()

router.post(
  '/upload',
  // dest爲上傳的目標目錄,single表示上傳單個文件,同時req對象中添加該文件。
  multer({ dest: `${UPLOAD_PATH}/book` }).single('file'),
  function (req, res) {
    // req.file爲一個數組
    if (!req.file || req.file.length === 0) {
      // 如果不存在,上傳失敗
      return
    } else {
      // 上傳成功
    }
  }
)

module.exports = router

多文件的上傳可以使用以下方法:

router.post('/', multer({
    //設置文件存儲路徑
    dest: 'upload'
}).array('file', 10), function (req, res, next) {  //這裏10表示最大支持的文件上傳數目
    let files = req.files;  //獲取文件的上傳信息
    if (files.length === 0) {
      // 上傳失敗
      return
  	  } else {
    	// 上傳成功
      }
    }
});

如果您也正在學習前端的路上,記得關注該博主,學習更多關於前端的知識~

博主主頁 Poetic Code

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章