目录
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格式的请求体,是经常使用的一个中间件。
基本使用方法:
- 安装
npm i -S body-parser
- 使用
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
基本使用方法:
- 安装
npm i -S cors
- 使用
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
基本使用方法:
- 安装mysql库
npm i -S mysql
- 配置
创建 db 目录,新建两个文件:index.js
,config.js
config.js
源码如下:
module.exports = {
host: 'localhost',
user: 'root',
password: '12345678',
database: 'book'
}
- 连接
连接数据库需要提供使用 mysql 库的 createConnection 方法,在 index.js 中创建如下方法:
function connect() {
return mysql.createConnection({
host,
user,
password,
database,
multipleStatements: true
})
}
multipleStatements:允许每条 mysql 语句有多条查询.使用它时要非常注意,因为它很容易引起 sql 注入(默认:false)
- 查询(查询需要调用 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
基本使用方法:
- 安装 crypto 库:
npm i -S crypto
- 创建 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
基本使用方法:
- 安装
npm install express-validator
- 验证
在请求当中的第二个参数添加一个数组,数组为校验规则,然后使用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
基本使用方法:
- 安装
npm i -S express-jwt
- 可以选择创建一个用于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
- 在需要用到的地方使用该中间件
const jwtAuth = require('./jwt')
// 注册路由
const router = express.Router()
// 对所有路由进行 jwt 认证
router.use(jwtAuth)
文件上传 multer
multer 用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
相关链接:https://github.com/expressjs/multer
基本使用方法:
- 安装
npm install -S multer
- 使用
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 {
// 上传成功
}
}
});
如果您也正在学习前端的路上,记得关注该博主,学习更多关于前端的知识~