上一篇文章中,简单介绍了express.js的使用,nodejs篇 express(1),其中提到了express中间件的使用。其实,在项目开发的过程中,使用express.js搭建的服务器,中间件的作用无处不在。
不同的应用场景和不同的调用方式,中间件可以分为以下几个类别:应用程序级别的中间件、路由级别的中间件、错误处理中间件、内置中间件、第三方中间件。学完之后呢,你就会对express中间件的应用得心应手。
这类中间件的作用范围包含整个服务器的所有接口,不关心请求的具体路由,也不关心请求的方法是什么,只要是请求的服务器地址和端口号没有错,都会执行的中间件函数。
示例
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl() {
return function (req, res, next) {
console.log(req.originalUrl);
next();
}
}
APP.use(getOriginalUrl());
APP.post("/api", function (req, res) {
res.set("Content-Type", "application/json");
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
APP.get("/user/:id", function (req, res) {
res.set("Content-Type", "application/json");
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
如上面的代码所示,无论客户端请求api还是user/:id,都会调用getOriginalUrl方法,将请求的路由打印出来。
针对特定的符合某一规则的路径,进行的函数封装处理。
var express = require("express");
var APP = express();
var PORT = 3000;
function getParams() {
return function (req, res, next) {
console.log(`动态路由`, req.params);
next();
};
}
// 只针对路径是/user/:id的中间件
APP.use("/user/:id", getParams());
APP.get("/user/:id", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
上述示例是只针对路径是/user/:id的中间件,当然use函数第一个参数不仅可以传低一个字符串,还可以传递一个正则,只要符合要求就会执行中间件。
这种是最常用的一种中间件使用方式
var express = require("express");
var app = express();
var port = 3000;
// express.json 就是中间件,用来处理客户端发送json数据在body中接收
app.post("/api", express.json(), function (req, res) {
console.log(req.body)
res.set("Content-Type", "application/json");
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
app.listen(port, function () {
console.log("server runing at 3000");
});
上面介绍的全局中间件或者是限定请求路径的中间件,或者是限定请求路径和请求方法的中间件,都可以一次性传入多个中间件。这些中间件在next() 执行后,就能够依次进行链式调用。
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl() {
return function (req, res, next) {
console.log(req.originalUrl, req.body);
next();
};
}
function setContentType(type) {
return function(req,res,next) {
res.set("Content-Type", type);
next()
}
}
// 全局使用多个中间件示例
APP.use(express.json(), getOriginalUrl(), setContentType("application/json"));
// 限定路径使用多个中间件示例
APP.use("/user/:id", express.json(), getOriginalUrl(), setContentType("application/json"));
// 限定路径和方法使用多个中间件示例
APP.get("/user/:id",express.json(), getOriginalUrl(), setContentType("application/json"), function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
感觉上面的写法还是有些麻烦,我们可以简化下
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl() {
return function (req, res, next) {
console.log(req.originalUrl, req.body);
next();
};
}
function setContentType(type) {
return function(req,res,next) {
res.set("Content-Type", type);
next()
}
}
var middlewares = [getOriginalUrl(), setContentType("application/json"), express.json()]
// 全局使用多个中间件示例
APP.use(middlewares);
// 限定路径使用多个中间件示例
APP.use("/user/:id", middlewares);
// 限定路径和方法使用多个中间件示例
APP.get("/user/:id", middlewares, function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
如果多个中间件,在某些情况下,我只想执行前两个中间件,不想执行第三个中间件,如何处理?
function getOriginalUrl() {
return function (req, res, next) {
console.log(req.originalUrl, req.body);
next();
};
}
function setContentType(type) {
return function (req, res, next) {
res.set("Content-Type", type);
// get请求时不接收前端传递过来的body参数,所以不需要处理客户端放在body中的json数据,也就是不需要express.json()
if (req.method === "GET") {
// 将会结束本次app.use的调用,跳过express.json()
next("route");
}
next();
};
}
var middlewares = [
getOriginalUrl(),
setContentType("application/json"),
express.json(),
];
APP.use(middlewares);
新建一个router.js,代码如下
var express = require("express");
// 创建路由实例
const router = express.Router();
// 配置路由
router.get("/user/:id", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
router.delete("/user/:id", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
router.post("/user", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
// 导出路由
module.exports = router;
在index.js中引入router,并绑定
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require('./router');
function getParams() {
return function (req, res, next) {
console.log(`动态路由`, req.params);
next();
};
}
APP.use("/user/:id", getParams());
// 挂载路由
APP.use(router)
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
当然,如果一系列全是user开头的路径,我们可以适当改造以下
router.js中
var express = require("express");
// 创建路由实例
const router = express.Router();
// 配置路由
router.get("/:id", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
router.delete("/:id", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
router.post("/", function (req, res) {
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
// 导出路由
module.exports = router;
index.js中
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require('./router');
function getParams() {
return function (req, res, next) {
console.log(`动态路由`, req.params);
next();
};
}
APP.use("/user/:id", getParams());
// 挂载路由
APP.use("/user", router);
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
改造完成的效果跟之前是一样的
var express = require("express");
var APP = express();
var PORT = 3000;
APP.delete("/user/:id", function (req, res, next) {
if (req.params.id === "0") {
next({
message: "该用户不存在"
});
}
res.status("200");
res.json({ code: 200, data: "请求成功了" });
});
// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
console.log("出错了", error.message);
res.status("500");
res.json({
message: error.message,
});
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
配置错误处理中间件的注意事项
调用错误处理中间件
'route'
的参数next()、next('route')、next(非route)
next有这三种调用方式,但功能各不相同,next()
就是走下一个中间件,next('route')
就是跳过接下来同一个app.use(app.get等)调用的多个后面的中间件,next(非route)
就是调用错误中间件状态码404比较特殊,它表示客户端请求的路由在服务器里没有匹配,因此,在express项目中,我们一般都需要在所有路由配置的最后,用中间件处理404的情况。
中间件处理404和错误处理中间件之间互不影响。
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require("./router");
// 挂载路由
APP.use(router);
// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
res.status('404').send("404 not found")
});
// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
console.log("出错了", error.message);
res.status("500");
res.json({
message: error.message,
});
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
express 4.x以后,内置中间件被缩减到了五个,它们分别是
比较常用的,其实就是 json urlencoded static
express.json 当客户端给你发送json数据时,需要在express中使用这个中间件后,才能在req.body中拿到数据
express.urlencoded 当客户端以表单的形式发送请求时,需要使用这个中间件。
express.static 当客户端向服务端发送文件时,需要使用
express官方介绍内置中间件地址
使用方式,一般在最上方使用常用的二个内置中间件
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require("./router");
//设置允许跨域访问该服务.
APP.all("*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "*");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
// 调用内置中间件
var middlewares = [
express.json(),
express.urlencoded()
];
APP.use(middlewares);
// 挂载路由
APP.use(router);
// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
res.status('404').send("404 not found")
});
// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
console.log("出错了", error.message);
res.status("500");
res.json({
message: error.message,
});
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
express官方维护了一些第三方中间件以及推荐的一些第三方中间件
https://expressjs.com/en/resources/middleware.html
以其中一个第三方中间件morgan为例,打印响应日志的一个中间件。
npm install morgan
var express = require("express");
var morgan = require("morgan");
var APP = express();
var PORT = 3000;
var router = require("./router");
//设置允许跨域访问该服务.
APP.all("*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "*");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
var middlewares = [express.json(), express.urlencoded()];
APP.use(middlewares, morgan(':method :url :status :res[content-length] - :response-time ms'));
// 挂载路由
APP.use(router);
// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
res.status("404").send("404 not found");
});
// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
console.log("出错了", error.message);
res.status("500");
res.json({
message: error.message,
});
});
APP.listen(PORT, function () {
console.log(`server runing at ${PORT}`);
});
nodejs commonjs介绍
nodejs fs模块介绍
nodejs path模块介绍
nodejs events模块介绍
nodejs http模块介绍
nodejs net模块介绍
nodejs url模块介绍
nodejs process模块介绍
nodejs buffer模块介绍
nodejs stream 模块介绍
nodejs express(1)模块介绍