总结
request object 代表 HTTP 请求,具有请求查询字符串、参数、正文、HTTP 标头等属性。
response object 表示 Express 应用在收到 HTTP 请求时发送的 HTTP 响应。
Middleware functions 是在应用程序的请求-响应周期中可以访问请求对象、响应对象和next 函数的函数。 next 函数是 Express 路由器中的一个函数,当被调用时,它会在当前中间件之后执行中间件。
路由可以附加chained methods(用于GET、POST 和DELETE 请求),将中间件函数作为参数。
请求对象是最初从请求中接收到的数据,可以通过各种中间件函数进行修改,响应对象是发送出去的数据。
示例中间件
下面是一个示例中间件函数,您可以在应用开头复制和粘贴:
/**
* An example of a middleware function that logs various values of the Express() request object.
*
* @constant
* @function
* @param {object} req - The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, the object is always referred to as req (and the HTTP response is res) but its actual name is determined by the parameters to the callback function in which you’re working.
* @param {object} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request. In this documentation and by convention, the object is always referred to as res (and the HTTP request is req) but its actual name is determined by the parameters to the callback function in which you’re working.
* @param {Function} next - `next` is used as an argument in the middleware function, and subsequently invoked in the function with `next()`, to indicate the application should "move on" to the next piece of middleware defined in a route's chained method.
* @see {@link https://expressjs.com/en/4x/api.html#req|Express Request}
* @see {@link https://expressjs.com/en/4x/api.html#res|Express Response}
* @see {@link http://expressjs.com/en/guide/writing-middleware.html|Writing Middleware}
*/
const my_logger = (req, res, next) => {
console.log("req.headers: ");
console.log(req.headers);
console.log("req.originalUrl: " + req.originalUrl);
console.log("req.path: " + req.path);
console.log("req.hostname: " + req.hostname);
console.log("req.query: " + JSON.stringify(req.query));
console.log("req.route: " + JSON.stringify(req.route));
console.log("req.secure: " + JSON.stringify(req.secure));
console.log("req.ip: " + req.ip);
console.log("req.method: " + req.method);
console.log("req.params:");
console.log(req.params);
console.log("==========================");
//if next() is not invoked below, app.use(myLogger) is the only middleware that will run and the app will hang
next();
}
// called for all requests
app.use(my_logger);
示例路线
以下是一些示例路线。
路由附加了chained methods,将中间件函数作为参数。
// some example routes
app.route("/api/:api_version/pages")
.get(api_pages_get);
app.route("/api/:api_version/topics")
.get(api_topics_get)
.post(api_login_required, api_topics_post)
.delete(api_login_required, api_topics_delete);
app.route("/api/:api_version/topics/ratings")
.post(api_login_required, api_topics_ratings_post);
在中间件函数中使用next()
在上面的例子中,你可以看到一些方法有两个中间件函数作为参数。
第一个 api_login_required 验证登录凭据,如果成功,则调用 next() 提示运行下一个中间件函数。
看起来像这样:
const api_login_required = (req, res, next) => {
// req.user exists if the user's request was previously verified, it is produced elsewhere in the code
if (req.user) {
next();
} else {
return res.status(401).json({ message: 'Unauthorized user!' });
}
}
没有next()的中间件
但是,附加到 /api/:api_version/pages 的路由处理程序的 get() 方法只有一个中间件函数参数:api_pages_get。
如下图,api_pages_get不调用next(),因为它之后不需要运行中间件函数。
它使用响应对象的send() 和json() 方法返回响应。
const api_pages_get = async (req, res) => {
var page_title = req.query.page_title;
var collection = mongo_client.db("pages").collection("pages");
var query = { page_title: page_title };
var options = { projection: { page_title: 1, page_html: 1 } };
try {
var page = await collection.findOne(query);
// if there is no result
if (page === null) {
res.status(404).send('404: that page does not exist');
return;
}
// if there is a result
else if (page !== null) {
res.json(page);
return;
}
} catch (err) {
console.log("api_pages_get() error: " + err);
res.send(err);
return;
}
}
中间件注意事项
我之前写的一些其他笔记供我自己参考,可能会有所帮助:
中间件或中间件函数可以访问 Express request 和 response 对象,并作为参数传递给路由的链式方法(如果作为参数传递给 use() 的实例,则在所有请求中传递)方法在代码的早期定义)。
next 用作中间件函数中的参数,随后在函数中使用next() 调用,以指示应用程序应该“继续”到定义在路由的链式方法中的下一个中间件。
如果一个中间件函数没有调用next(),它就不会移动到路由或方法处理程序中定义的下一个中间件。
另外,如果没有使用next(),并且函数中没有定义终止动作,即响应,则应用将处于“挂起”状态。