likes
comments
collection
share

全栈之路:Node.js + express 项目中常用的中间件

作者站长头像
站长
· 阅读数 15

1. dotenv

dotenv 用于按需加载不同的环境变量文件,用法如下:

npm install dotenv

在项目根目录新建 .env 文件

全栈之路:Node.js + express 项目中常用的中间件

全栈之路:Node.js + express 项目中常用的中间件

在 app.js 文件中使用:process.env.DEV_PORT,默认读取项目根目录下的.env文件

const express = require('express')

const dotenv = require('dotenv')
dotenv.config()

const app = express()

app.listen(process.env.DEV_PORT, () => {
  console.log(`项目启动成功: ${process.env.DEV_URL}:${process.env.DEV_PORT}`)
})

如果包含环境变量的文件位于其他位置,请指定自定义路径:

const dotenv = require('dotenv')
dotenv.config({ path: '/custom/path/to/.env' })

2. chalk

chalk 用于改变console输出的样式,用法如下:

npm install chalk
const chalk = require("chalk")

log(chalk.red("sea"))  // 字体颜色
log(chalk.bgGreen("Forest")) // 背景色
log(chalk.bold.underline.bgYellow.red("WARNING!"))

全栈之路:Node.js + express 项目中常用的中间件

3. mount-routes

mount-routes 可以自动挂载 routes 目录的所有路由,以文件名称作为路由的根,也可以指定具体的路径(使用第二个参数)

全栈之路:Node.js + express 项目中常用的中间件

npm install mount-routes
const express = require('express')
const mount = require('mount-routes') // 路由加载

const app = express()

// 1.简单用法
mount(app)

// 2.带路径的用法
// 可以打印出路由表,true代表展示路由表在打印台
mount(app, path.join(process.cwd(), '/routes'), true)

4. cors

cors 主要用于解决跨域问题,原理:CORS 中间件配置在服务端,由一系列 HTTP 响应头组成,这个响应头可以决定浏览器是否阻止前端 JS 代码跨域获取资源,当接口服务器配置了 CORS 中间件之后,发起请求时就会自动配置相应的请求头,进而解除浏览器的跨域访问限制。

当浏览器进行跨域请求的时候,会在请求里添加头部 origin,表明自己协议,主机,端口。当服务器收到这个客户端发送的请求之后,如果需要允许能够访问,就需要添加头部信息 Access-Control-Arrow-Origin 到响应里面,浏览器收到传回来的这个头部信息就知道能不能进行跨域请求了。

npm install cors
const express = require('express')
const cors = require('cors')

const app = express()
app.use(cors())
app.all('/api/*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*') // 配置跨域
  res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS') // 允许请求的方法
  res.header('Access-Control-Allow-Headers', 'X-Requested-With, token')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With, Authorization')
  res.header('Content-Type', 'application/json;charset=UTF-8')
  res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With')
  if (req.method == 'OPTIONS') res.send(200)
  /*让options请求快速返回*/ else next()
})

5. body-parser

body-parser 用于处理 post 请求提交的数据,把数据保存在 req.body 中,以一个对象的形式提供给服务器,方便进行后续的处理。由于无论用户提交什么都会接受,所以需要在使用数据前进行验证来提高安全性。

此中间件已经被 express 集成,无需调用安装 body-parser,可以直接采用 express.json() 和 express.urlencoded() 实现相同功能,东西都是一样的,所以这里还是使用 body-parser 来介绍,下面我们来看一下 body-parser 常见的 API:

(1)bodyParser.json([options]):解析并返回 json格式的数据,只有 content-type: application/json 才进入这个中间件解析处理

全栈之路:Node.js + express 项目中常用的中间件 (2)bodyParser.urlencoded([options]):表单 post 提交、axios、fetch 等库的 post 请求都需要这个中间件进行解析,返回json的格式数据,当请求的数据类型是application/x-www-form-urlencoded时才会进入这个中间件进行处理。

全栈之路:Node.js + express 项目中常用的中间件

npm install body-parser
const express = require('express')
const bodyParser = require('body-parser') // 对http请求体进行解析
const app = express()

//处理请求参数解析
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))

6. express-jwt + jsonwebtoken

jsonwebtoken:生成 JWT 字符串(在服务器中将用户的信息转成 JWT 字符串) express-jwt:将 JWT 字符串解析还原成 JSON 对象(使用客户端保留的 JWT 加密字段,还原成真正的用户信息)

npm install express-jwt
npm install jsonwebtoken

(1)定义 secret 密钥:为了保证 JWT 字符串的安全性,防止 JWT 字符串传输的过程中被人破解,我们需要专门定义一个用于加密和解密的 secret 密钥。当生成 JWT 字符串的时候,需要使用 secret 密钥对用户的信息进行加密,最终得到加密好的 JWT 字符串;当把 JWT 字符串解析还原成 JSON 对象的时候,需要对 secret 密钥进行解密(使用和前面加密相同的密钥),密钥定义成字符串即可:

全栈之路:Node.js + express 项目中常用的中间件

SIGN_KEY = 'gLR+JUuKR/R5KrA1gr4ukg=='

(2)登录成功后生成JWT字符串--生成Token

const jwt = require('jsonwebtoken')

exports.login = function (pm, cb) {
    //登录逻辑
    Users.findOne({where: {username: pm.username,}}).then(data => {
        //判断用户是否正常
        if (!data.state) {
            cb(null, '账户已被禁用!请联系管理员')
            logger.error('账户已被禁用!请联系管理员')
            return;
        }
        if (pm.password === data.password) {
            // 生成token
            let token = 'Bearer ' + jwt.sign(
                {
                    username: pm.username,
                    password: pm.password,
                    admin: true
                },
                process.env["SIGN_KEY"],
                {
                    expiresIn: 3600 * 24 * 3 //3天
                    // expiresIn: 30 //30s
                }
            )
            let userInfo = data
            //登录成功
            cb({userInfo, token})
            return
        }
        logger.error('密码错误')
        cb(null, '密码错误!')
    }).catch(err => {
        logger.error(JSON.stringify(err))
        cb(null, '用户不存在!请联系管理员添加')
    })
}

(3)将JWT字符串还原成为JSON对象--解析Token

const expressJwt = require('express-jwt')

/**
 * token验证函数
 *
 * @param  {[type]}   req  请求对象
 * @param  {[type]}   res  响应对象
 * @param  {Function} next 传递事件函数
 */


exports.tokenAuth =expressJwt({
    secret: process.env["SIGN_KEY"],
    algorithms: ['HS256'],
    credentialsRequired: true, //对没有携带token的 接口不抛出错误
})

(4)捕获解析JWT失败后产生的错误——错误中间件在最后 进行捕获错误:当使用express-jwt 解析 Token 字符串时,如果客户端发送过来的 Token 字符串过期或不合法,会产生一个解析失败的错误,影响项目的正常运行,可以通过 Express 的错误中间件,捕获这个错误并进行相关的处理。

app.use(function (err, req, res, next) {
    if (err.name === 'UnauthorizedError') {
        logger.error(`${req.method} ${req.baseUrl + req.path} *** 响应:${JSON.stringify({
            data: null,
            code: err.status || 401,
            message: err.message || 'token错误'
        })}`);
        res.status(401).send({data: null, code: err.status || 401, message: err.message || 'token错误'})
    }
})

7. log4js

log4js 是一种 Node 日志管理工具,可以将自定义格式的日志输出到各种渠道。对于控制台的日志输出可以呈现彩色日志,对于文件方式的日志输出,可以根据文件大小或者日期进行日志切割。我们先来熟悉一下几个 log4js 中的概念。

(1)Level:日志的分级,更好地为展示日志(不同级别的日志在控制台中采用不同的颜色,比如 error 通常是红色的)

全栈之路:Node.js + express 项目中常用的中间件

(2)catetory:日志的类型,在通过 getLogger 获取 Logger 实例时,唯一可以传的一个参数就是 loggerCategory(如'example'),通过这个参数来指定 Logger 实例属于哪个类别。

var log4js = require('log4js')
var logger = log4js.getLogger('example')
logger.debug("Time:", new Date())

全栈之路:Node.js + express 项目中常用的中间件

(3)appenders:日志输出到哪里,默认将日志都输出到了控制台,在项目的根目录新建 logs 文件,作为日志的出口。

全栈之路:Node.js + express 项目中常用的中间件

var log4js = require('log4js');

log4js.configure({
    appenders: {
        console: { type: 'console' },
        info: {
            type: 'file',
            filename: 'logs/info.log'
        },
        error: {
            type: 'file',
            filename: 'logs/error.log'
        }
    },
    categories: {
        default: {
            appenders: [ 'console','info' ],
            level: 'debug'
        },
        info: {
            appenders: ['info'],
            level: 'info'
        },
        error: {
            appenders: [ 'error', 'console' ],
            level: 'error'
        }
    }
});

封装logger.js工具函数:在项目根目录的 utils 文件夹中新建 utils.logger.js 文件

全栈之路:Node.js + express 项目中常用的中间件

npm install log4js
var log4js = require('log4js');

log4js.configure({
    appenders: {
        console: { type: 'console' },
        info: {
            type: 'file',
            filename: 'logs/info.log'
        },
        error: {
            type: 'file',
            filename: 'logs/error.log'
        }
    },
    categories: {
        default: {
            appenders: [ 'console','info' ],
            level: 'debug'
        },
        info: {
            appenders: ['info'],
            level: 'info'
        },
        error: {
            appenders: [ 'error', 'console' ],
            level: 'error'
        }
    }
});

/**
 * 日志输出 level为bug
 * @param { string } content
 */
exports.debug = ( content ) => {
    let logger = log4js.getLogger('debug')
    logger.level = 'debug'
    logger.debug(content)
}

/**
 * 日志输出 level为info
 * @param { string } content
 */
exports.info = ( content ) => {
    let logger = log4js.getLogger('info')
    logger.level = 'info'
    logger.info(content)
}

/**
 * 日志输出 level为error
 * @param { string } content
 */
exports.error = ( content ) => {
    let logger = log4js.getLogger('error')
    logger.level = 'error'
    logger.error(content)
}

在项目中使用

全栈之路:Node.js + express 项目中常用的中间件

logs/info.log

全栈之路:Node.js + express 项目中常用的中间件

logs/error.log

全栈之路:Node.js + express 项目中常用的中间件

8. nodemailer

Nodemailer 是一个简单易用的 Node.JS 邮件发送模块(通过 SMTP,sendmail,或者 Amazon SES),官方提供了一套固定的模板。

封装nodemailer.js工具函数

全栈之路:Node.js + express 项目中常用的中间件

const nodemailer = require("nodemailer");
/**
 * 邮箱发送
 *
 * @param  {Object}  pm 对方信息
 */

exports.sendMailer = (pm) => {
    return new Promise((resolve, reject) => {
        // 创建Nodemailer传输器 SMTP 或者 其他 运输机制
        let transporter = nodemailer.createTransport(
            {
                service: 'QQ', // 使用内置传输发送邮件 查看支持列表:https://nodemailer.com/smtp/well-known/
                port: 465, // SMTP 端口
                secureConnection: true, // 使用 SSL
                auth: {
                    user: '1840354092@qq.com', // 发送方邮箱的账号
                    pass: '******', // 邮箱授权密码
                }
            }
        );
        // 定义transport对象并发送邮件
        transporter.sendMail({
            from: `"MG'Blog" <1840354092@qq.com>`, // 发送方邮箱的账号
            to: pm.email, // 邮箱接受者的账号
            subject: "MG'Blog", // Subject line
            // text: '"MG'Blog 👻"', // 文本内容
            html: `<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSy_130iiorSSjF1RWgNBX7qy3evKv2HKsH0g&usqp=CAU">
        <p style="text-indent: 2em;">您好! "${pm.email}" </p>
        <p style="text-indent: 2em;">您在<a href="http://www.zhouyi.run/#/">MG'Blog</a>上的留言博主已收到🎈 感谢您的支持!</p>
        <p >✨回复内容:</p>
        <p style="text-indent: 2em;">${pm.content}</p>
        <p style="text-indent: 2em;">祝您工作顺利,心想事成🎉🎉🎉</p>
        <p style="text-align: right;">—— <a href="http://www.zhouyi.run/#/">MG'Blog</a></p>`,
        }, (error, info) => {
            if (error) {
                reject(error)
            }
            resolve(info)
        });
    })
}

在项目中使用

全栈之路:Node.js + express 项目中常用的中间件

9. multer

multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。

10. express-swagger-generator

express-swagger-generator 可以自动生成 api 文档

全栈之路:Node.js + express 项目中常用的中间件

const options = {
    swaggerDefinition: {
        info: {
            title: 'mg-api',
            version: '1.0.0',
            description: `芒果快熟’接口api`
        },
        host: `${process.env.SWEG_URL}:${process.env.DEV_PORT}`,
        basePath: '/',
        produces: ['application/json', 'application/xml'],
        schemes: ['http', 'https'],
        securityDefinitions: {
            JWT: {
                type: 'apiKey',
                in: 'header',
                name: 'Authorization',
                description: ''
            }
        }
    },
    route: {
        url: '/swagger',//打开swagger文档页面地址
        docs: '/swagger.json' //swagger文件 api
    },
    basedir: __dirname, //app absolute path

    files: [  //在那个文件夹下面收集注释
        '../../routes/api/private/*.js',
        '../../routes/api/public/**/*.js',
    ]
}

module.exports = options

app.js

const express = require('express')
const app = express()

const expressSwagger = require('express-swagger-generator')(app)
const options = require('./utils/swagger') //配置信息
expressSwagger(options)

11. crypto-js

crypto-js 是谷歌开发的一个纯 JavaScript 的加密算法类库,可以非常方便的在前端进行其所支持的加解密操作。目前已支持的算法包括:

  • MD5

  • SHA-1

  • SHA-256

  • AES

  • HMAC

    • HMAC-MD5
    • HMAC-SHA1
    • HMAC-SHA256

封装加密/解密工具函数

全栈之路:Node.js + express 项目中常用的中间件

npm install crypto-js
/**
 * 通过crypto-js实现 加解密工具
 * AES、HASH(MD5、SHA256)、base64
 * @author: hzd
 */
const CryptoJS = require('crypto-js') // 加密

let KP = {
  key: '90268d3dc304f5f3', //process.env.VUE_APP_AES_KEY, // 秘钥 16*n:
  iv: 'b894f52b46104ab2', //process.env.VUE_APP_AES_IV  // 偏移量
}

function getAesString(data, key, iv) {
  // 加密
  key = CryptoJS.enc.Utf8.parse(key)
  // alert(key);
  iv = CryptoJS.enc.Utf8.parse(iv)
  let encrypted = CryptoJS.AES.encrypt(data, key, {
    iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  })
  return encrypted.toString() // 返回的是base64格式的密文
}

function getDAesString(encrypted, key, iv) {
  // 解密
  key = CryptoJS.enc.Utf8.parse(key)
  iv = CryptoJS.enc.Utf8.parse(iv)
  let decrypted = CryptoJS.AES.decrypt(encrypted, key, {
    iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  })
  return decrypted.toString(CryptoJS.enc.Utf8)
}

// AES 对称秘钥加密
const aes = {
  //加密
  en: data => getAesString(data, KP.key, KP.iv),
  //解密
  de: data => getDAesString(data, KP.key, KP.iv),
}
// BASE64
const base64 = {
  en: data => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)),
  de: data => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8),
}
// SHA256
const sha256 = data => {
  return CryptoJS.SHA256(data).toString()
}
// MD5 '12654987' --> 60f6c0f4991073bdb49b56b3d38f2645
const md5 = data => {
  return CryptoJS.MD5(data).toString()
}

/**
 * 签名
 * @param token 身份令牌
 * @param timestamp 签名时间戳
 * @param data 签名数据
 */
const sign = (token, timestamp, data) => {
  // 签名格式: timestamp + token + data(字典升序)
  let ret = []
  for (let it in data) {
    let val = data[it]
    if (
      typeof val === 'object' && //
      (!(val instanceof Array) || (val.length > 0 && typeof val[0] === 'object'))
    ) {
      val = JSON.stringify(val)
    }
    ret.push(it + val)
  }
  // 字典升序
  ret.sort()
  let signsrc = timestamp + token + ret.join('')
  return md5(signsrc)
}
module.exports = {
  aes,
  md5,
  sha256,
  base64,
  sign,
}

12. express-session

express-session 是针对 express 框架提供的一套 session 扩展,session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存在服务器上。express-session 这个中间件替代 cookie-parser 和 cookie-session 中间件成为处理用户状态的首选。

session 的工作流程:当浏览器访问服务器时,服务器创建一个 session 对象(该对象有一个唯一的id号 sessionId),服务器会将 sessionId 以 cookie 的方式(set-cookie消息头)发送给浏览器,浏览器会将sessionId 保存到内存;当浏览器再次访问服务器时,会将 sessionId 发送给服务器,服务器依据sessionId 就可找到之前创建的 session 对象。

express-session的使用

npm install express-session
const session = require('express-session')
const express = require('express')
const fs = require('fs')

const app = express()

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: false, maxAge: 800000 },
    name: 'ivan'
}))

app.get('/', (req, res) => {
    const html = fs.readFileSync('./views/index.html', 'utf-8')
    const session = req.session  // 获得session
    session['key'] = 'value'  // 设置session
    res.setHeader('set-cookies', session['key']) // 保存cookie在headers中
    res.end(html)  // 发送给客户端
})

app.listen(3000)

express-session的常用参数

全栈之路:Node.js + express 项目中常用的中间件

转载自:https://juejin.cn/post/7228826435866837048
评论
请登录