Express
中间件的组成
中间件函数可以执行以下任何任务:
- 执行任何代码
- 修改 request 或者 response 响应对象
- 结束请求响应周期
- 调用下一个中间件
中间件分类
- 应用程序级别中间件
- 路由级别中间件
- 错误处理中间件
- 内置中间件
- 第三方中间件
应用程序级别中间件
不关心请求路径:
var app = express(); app.use(function(req, res, next) { console.log("Time:", Date.now()); next(); });
限定请求路径:
app.use("/user/:id", function(req, res, next) { console.log("Request Type:", req.method); next(); });
限定请求方法:
app.get("/user/:id", function(req, res, next) { res.send("USER"); });
多个处理函数:
app.use( "/user/:id", function(req, res, next) { console.log("Request URL:", req.originalUrl); next(); }, function(req, res, next) { console.log("Request Type:", req.method); next(); } );
多个路由处理函数:
app.get( "/user/:id", function(req, res, next) { console.log("ID:", req.params.id); next(); }, function(req, res, next) { res.send("User Info"); } ); // handler for the /user/:id path, which prints the user ID app.get("/user/:id", function(req, res, next) { res.end(req.params.id); });
最后一个例子:
app.get( "/user/:id", function(req, res, next) { // if the user ID is 0, skip to the next route if (req.params.id === "0") next("route"); // otherwise pass the control to the next middleware function in this stack else next(); }, function(req, res, next) { // render a regular page res.render("regular"); } ); // handler for the /user/:id path, which renders a special page app.get("/user/:id", function(req, res, next) { res.render("special"); });
路由级别中间件
创建路由实例:
var router = express.Router();
示例:
var app = express(); var router = express.Router(); // a middleware function with no mount path. This code is executed for every request to the router router.use(function(req, res, next) { console.log("Time:", Date.now()); next(); }); // a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path router.use( "/user/:id", function(req, res, next) { console.log("Request URL:", req.originalUrl); next(); }, function(req, res, next) { console.log("Request Type:", req.method); next(); } ); // a middleware sub-stack that handles GET requests to the /user/:id path router.get( "/user/:id", function(req, res, next) { // if the user ID is 0, skip to the next router if (req.params.id === "0") next("route"); // otherwise pass control to the next middleware function in this stack else next(); }, function(req, res, next) { // render a regular page res.render("regular"); } ); // handler for the /user/:id path, which renders a special page router.get("/user/:id", function(req, res, next) { console.log(req.params.id); res.render("special"); }); // mount the router on the app app.use("/", router);
另一个示例:
var app = express(); var router = express.Router(); // predicate the router with a check and bail out when needed router.use(function(req, res, next) { if (!req.headers["x-auth"]) return next("router"); next(); }); router.get("/", function(req, res) { res.send("hello, user!"); }); // use the router and 401 anything falling through app.use("/admin", router, function(req, res) { res.sendStatus(401); });
错误处理中间件
app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send("Something broke!"); });
内置中间件
- express.static serves static assets such as HTML files, images, and so on.
- express.json parses incoming requests with JSON payloads. NOTE: Available with Express 4.16.0+
- express.urlencoded parses incoming requests with URL-encoded payloads. NOTE: Available with Express 4.16.0+
官方支持的中间件列表:
- https://github.com/senchalabs/connect#middleware
第三方中间件
官方中间件资源:http://expressjs.com/en/resources/middleware.html
早期的 Express 内置了很多中间件。后来 Express 在 4.x 之后移除了这些内置中间件,官方把这些功能性中间件以包的形式单独提供出来。这样做的目的是为了保持 Express 本身极简灵活的特性,开发人员可以根据自己的需求去灵活的定制。下面是官方提供的一些常用的中间件解决方案。
Middleware module |
Description |
Replaces built-in function (Express 3) |
body-parser |
Parse HTTP request body. See also: body , co-body , and raw-body . |
express.bodyParser |
compression |
Compress HTTP responses. |
express.compress |
connect-rid |
Generate unique request ID. |
NA |
cookie-parser |
Parse cookie header and populate . See also cookies and keygrip . |
express.cookieParser |
cookie-session |
Establish cookie-based sessions. |
express.cookieSession |
cors |
Enable cross-origin resource sharing (CORS) with various options. |
NA |
csurf |
Protect from CSRF exploits. |
express.csrf |
errorhandler |
Development error-handling/debugging. |
express.errorHandler |
method-override |
Override HTTP methods using header. |
express.methodOverride |
morgan |
HTTP request logger. |
express.logger |
multer |
Handle multi-part form data. |
express.bodyParser |
response-time |
Record HTTP response time. |
express.responseTime |
serve-favicon |
Serve a favicon. |
express.favicon |
serve-index |
Serve directory listing for a given path. |
express.directory |
serve-static |
Serve static files. |
express.static |
session |
Establish server-based sessions (development only). |
express.session |
timeout |
Set a timeout period for HTTP request processing. |
express.timeout |
vhost |
Create virtual domains. |
express.vhost |
中间件应用
输出请求日志中间件
功能:实现为任何请求打印请求日志的功能。
logger.js
定义并导出一个中间件处理函数:
module.exports = (req, res, next) => { console.log(`${req.method} -- ${req.path}`); next(); };
app.js
加载使用中间件处理函数:
app.use(logger);
统一处理静态资源中间件
功能:实现 express.static() 静态资源处理功能
static.js
定义并导出一个中间件处理函数:
const fs = require("fs"); const path = require("path"); module.exports = function static(pathPrefix) { return function(req, res, next) { const filePath = path.join(pathPrefix, req.path); fs.readFile(filePath, (err, data) => { if (err) { // 继续往后匹配查找能处理该请求的中间件 // 如果找不到,则 express 会默认发送 can not get xxx return next(); } res.end(data); }); }; };
app.js
加载并使用 static 中间件处理函数:
// 不限定请求路径前缀 app.use(static("./public")); app.use(static("./node_modules")); // 限定请求路径前缀 app.use("/public", static("./public")); app.use("/node_modules", static("./node_modules"));
错误处理
参考文档:
- Error handling
常用 API
参考文档:
- 4.x API
express
- express.json
- express.static
- express.Router
- express.urlencoded()
Application
- app.set
- app.get
- app.locals
Request
- req.app
- req.query
- req.body
- req.cookies
- req.ip
- req.hostname
- Req.method
- req.params
- req.path
- req.get()
Response
- res.locals
- res.append()
- res.cookie()
- res.clearCookie()
- res.download()
- res.end()
- res.json()
- res.jsonp()
- res.redirect()
- res.render()
- res.send()
- res.sendStatus()
- res.set()
- res.status()
Router
- router.all()
- router.METHOD()
- router.use()