Express Middleware 只是将多个函数串联起来的一种巧妙方式。三分钟就能解释清楚 😎
中间件 == 带有函数next()
示例 1:对某些路由要求用户身份验证。
示例 2:要求所有路由都进行用户身份验证。
示例 3:将 JSON 请求体解析为对象。
示例 4:可配置中间件
让我们从创建世界上最简单的 Express 服务器开始:
import express from "express";
const app = express();
app.get('/hello', (req, res) => {
res.send('world'));
}
它创建了一条/hello响应身体的路线world。
现在让我们稍微修改一下最后一行,添加一个名为“:”的第三个参数next。
app.get('/hello', (req, res, next) => {
res.send('world'));
next();
}
恭喜!🎉🎉🎉 您刚刚创建了一个 Express 中间件。就这么简单!
中间件 == 带有函数next()
中间件就是一个带有三个参数的函数(req, res, next),next它允许你链式调用多个函数。我们来看另一个例子:
// returns true if server time is in AM
function isMorning() {...}
app.get("/hello",
// middleware #1
(req, res, next) => {
if (isMorning()) {
res.send("morning");
} else {
next();
}
},
// middleware #2: called when isMorning() === false
(req, res, next) => {
res.send("afternoon");
}
);
这里我们链接了两个中间件函数来处理/hello路由。我们使用 `if` 语句next()将控制权从第一个中间件传递给第二个中间件。
在实际应用中,中间件对于在不同路由之间共享通用代码非常有用。
示例 1:对某些路由要求用户身份验证。
这里我们创建了一个中间件,它仅next()在用户通过身份验证后才会调用。该中间件由两个路由共享。请注意,当用户未通过身份验证时,我们不会调用该中间件next(),这将终止整个调用链。
function RequireUserAuthentication(req, res, next) {
if (req.user == null) {
res.status("401").send("User is unauthenticated.");
} else {
next();
}
}
app.get("/me/name", RequireUserAuthentication, (req, res, next) => {
res.send(req.user.name);
});
app.get("/me/avatar", RequireUserAuthentication, (req, res, next) => {
res.send(req.user.avatar);
});
如果我们想在所有路由上而不是特定路由上使用 RequireUserAuthentication,该怎么办?
示例 2:要求所有路由都进行用户身份验证。
我们可以使用中间件app.use(RequireUserAuthentication),将其RequireUserAuthentication“注入”到所有路由中。
需要注意的是,中间件是有顺序的。在下面的代码中,任何之前定义的路由app.use(RequireUserAuthentication)都不会受到影响。
// This route is not affected by RequireUserAuthentication
app.get("/home", (req, res, next) => res.send(...));
// Require user auth for all routes defined after this line.
app.use(RequireUserAuthentication);
// Routes below are user sign-in required
app.get("/me/name", (req, res, next) => {
res.send(req.user.name);
});
app.get("/me/avatar", (req, res, next) => {
res.send(req.user.avatar);
});
示例 3:将 JSON 请求体解析为对象。
有时将请求体自动转换为 JSON 对象很有用,这样我们就不必为每个路由编写相同的逻辑了:
// Converts request body into req.body as a javascript object
function JSONParser(req, res, next) {
if (req.headers['content-type'].startsWith('application/json')) {
const rawBody = readStreamIntoString(req);
req.body = JSON.parse(rawBody);
}
next();
}
// Apply JSONParser middleware to all routes defined after this line
app.use(JSONParser);
// Reads post name and content from req.body
app.get("/new/post", (req, res, next) => {
const postTitle = req.body.title;
const postContent = req.body.content;
...
});
// Reads username from req.body
app.get("/new/user", (req, res, next) => {
const userName = req.body.username;
...
});
这里我们创建了一个JSONParser中间件,它将 JSON 请求体解析成一个对象,并将该对象设置为。之后,该对象会从路由以及之后定义的任何其他路由req.body中读取。/new/post
示例 4:可配置中间件
让我们来点儿花样,创建一个“工厂”函数来返回中间件函数。一个函数的函数🤖
function BodyParser(options) {
if (options.type === "JSON") {
return (req, res, next) => {
if (req.headers["content-type"].startsWith("application/json")) {
const rawBody = readStreamIntoString(req);
req.body = JSON.parse(rawBody);
}
next();
};
} else if (options.type === "URL_ENCODED") {
return (req, res, next) => {
if (
req.headers["content-type"].startsWith(
"application/x-www-form-urlencoded"
)
) {
const rawBody = readStreamIntoString(req);
req.body = new URLSearchParams(rawBody);
}
next();
};
}
}
app.use(BodyParser({ type: "JSON" }));
app.use(BodyParser({ type: "URL_ENCODED" }));
在上面的代码中,我们允许传入一个options参数来控制要返回哪个中间件函数。
事实上,bodyParser正是通过解析请求体来实现这一点的(当然,它的代码更加复杂)。
你们在生产环境中使用了哪些中间件函数?请在下方留言分享你们最喜欢的函数❤️❤️❤️!
快来访问getd.io,并留下您对未来功能需求的反馈意见❤️❤️❤️!
文章来源:https://dev.to/getd/express-middleware-is-just-a-fancy-way-of-chaining-a-bunch-of-functions-explained-in-3-mins-43jf