【node学习-06】express进阶
express中间件
在
Express
中,中间件是一个功能强大的概念,它允许你在请求被处理之前或之后执行代码。中间件函数可以访问请求对象(req)
、响应对象(res)
,以及应用中的下一个中间件函数(next)
。
假如我想在Express
项目的每一次请求中,添加一个打印日志的功能,如果在所有的请求中console
打印肯定不现实,不如抽出一个logs
方法,然后在每次请求时候去调用:
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000
function logs(req, res) {
console.log(`${req.method},${req.url}, ${new Date().toLocaleString()}`)
}
app.get('/', (req, res) => {
logs(req, res)
res.send('Hello World')
})
app.get('/login', (req, res) => {
logs(req, res)
res.send('login')
})
app.get('/register', (req, res) => {
logs(req, res)
res.send('register')
})
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
但是这样的方式还是有些不方便;需要在每次请求中都去调用logs
方法,不仅不方便,而且还会有很多重复的代码。
所以,我们可以把logs
方法作为一个中间件,然后在app.use()
中使用它:
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000
function logs(req, res, next) {
console.log(`${req.method},${req.url}, ${new Date().toLocaleString()}`)
// 下一步操作
next()
}
app.use(logs)
app.get('/', (req, res) => {
res.send('Hello World')
})
app.get('/login', (req, res) => {
res.send('login')
})
app.get('/register', (req, res) => {
res.send('register')
})
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
在 Express
中,中间件可以写在 app.get
方法之前、之后或之间,具体取决于中间件的作用和你希望它在请求处理过程中的执行顺序。
中间件分类
在 Express 框架中,中间件(Middleware)是一个函数,在请求被发送到路由处理程序之前,可以对请求进行预处理、处理请求、或者对响应进行后处理。Express 中间件可以分为以下几种类型:
-
应用级中间件:应用级中间件绑定到 Express 的应用实例(app 对象)上,它们通过
app.use()
方法使用。这种中间件能够处理应用中的所有请求,对请求和响应进行修改,执行一些公共任务,比如日志记录、身份验证等。 -
路由级中间件:路由级中间件与应用级中间件类似,但它绑定到特定的路由上,只能处理特定路由的请求。通过
app.use()
或者router.use()
方法使用,它能够为特定路由的请求执行特定的任务,比如验证用户权限、数据验证等。 -
错误处理中间件:错误处理中间件专门用于处理请求过程中发生的错误。当一个中间件通过
next(err)
方法传递错误时,错误处理中间件将被调用。它接收四个参数(err, req, res, next),并负责处理错误、生成错误响应以及记录错误日志等操作。 -
内置中间件:Express 框架内置了一些常用的中间件,比如
express.static
(用于提供静态文件服务)、express.json
(用于解析 JSON 请求体)、express.urlencoded
(用于解析 URL 编码的请求体)等。这些内置中间件可以通过简单的配置来使用,提供了一些基本的功能,可以快速开发 Web 应用。 -
第三方中间件:除了内置中间件之外,Express 还支持第三方中间件,开发者可以通过 npm 安装并使用第三方中间件来扩展 Express 的功能。第三方中间件可以实现各种功能,比如身份验证、日志记录、性能监控等,丰富了 Express 生态系统,为开发者提供了更多选择。
应用级中间件
在 Express 中,应用级中间件直接与 Express 应用的实例相关,对整个应用生效。它们通常通过 app.use
或者对特定的路由使用 app.METHOD
(例如 app.get
)来注册。以下是一个简单的例子:
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// 应用级中间件
app.use((req, res, next) => {
console.log('This middleware is executed for every request to the app.');
next(); // 调用 next() 将控制权传递给下一个中间件或路由处理程序
});
app.get('/user', (req, res, next) => {
console.log('Handling user request...');
next();
}, (req, res) => {
res.send('User route response');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
在这个例子中,app.use
注册了一个应用级中间件,它在每个请求到达应用时都会执行。对于 /user
路由,我们通过 app.get
注册了两个中间件,其中第一个中间件在 /user
请求前执行,记录了请求的处理过程。
应用级中间件可以用于执行一些全局的任务,比如记录日志、身份验证、处理请求等。由于它们在整个应用范围内生效,因此适用于需要在每个请求中执行的任务。
路由级中间件
在 Express 中,路由级中间件是与特定路由或路由组相关的中间件。它们通过 express.Router
创建,并通过 app.use
或者 app.METHOD
(例如 app.get
)来注册。以下是一个简单的应用:
新建/router/index.js
和/router/video.js
文件,内容如下:
/router/index.js
:
const express = require('express')
const router = express.Router()
router.get('/user', (req, res) => {
console.log(req.method)
res.send('success')
})
router.get('/login', (req, res) => {
console.log(req.method)
res.send('login success')
})
module.exports = router
/router/video.js
:
const express = require('express')
const router = express.Router()
router.get('/list', (req, res) => {
console.log(req.method)
res.send('list success')
})
router.get('/detail', (req, res) => {
console.log(req.method)
res.send('detail success')
})
module.exports = router
然后在app.js
中引入并注册,同时注册时候给他们前面分别添加两个前缀/api
和/video
:
const express = require('express')
const router = require('./router/index')
const videoRouter = require('./router/video')
const app = express()
app.use('/api', router)
app.use('/video', videoRouter)
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
错误处理中间件
在 Express 中,错误处理中间件是指处理错误的中间件,它可以处理请求和响应,并对它们进行修改。
错误处理中间件可以捕获应用中的错误,并将其发送给客户端。以下是一个简单的例子:
const express = require('express')
const router = require('./router/index')
const videoRouter = require('./router/video')
const app = express()
app.use('/api', router)
app.use('/video', videoRouter)
//捕获路由错误
app.use((req, res, next) => {
res.status(404).send({
message: 'Not Found'
})
})
//捕获错误
app.use((err, req, res, next) => {
res.status(500).send({
message: 'server error'
})
})
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
内置中间件
Express 内置的中间 件主要用于处理常见的任务,如解析请求体、处理静态文件等。以下是一些常见的 Express 内置中间件:
1. express.json()
用于解析传入请求的 JSON 数据,并将其放置在 req.body
中。
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/data', (req, res) => {
console.log(req.body); // 访问 JSON 数据
res.send('Data received successfully.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
2. express.urlencoded()
用于解析传入请求的 URL 编码数据(通常来自表单),并将其放置在 req.body
中。
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.post('/api/form', (req, res) => {
console.log(req.body); // 访问表单数据
res.send('Form data received successfully.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
3. express.static()
用于提供静态文件,例如 HTML、CSS、JavaScript 等。
const express = require('express');
const app = express();
app.use(express.static('public'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
4. express.Router()
虽然不是直接中间件,但用于创建模块化、可挂载的路由处理程序。
// 在 router.js 文件中
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Router response');
});
module.exports = router;
// 在主应用中
const express = require('express');
const app = express();
const router = require('./router');
app.use('/api', router);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
这些内置中间件使得 Express 应用更易于开发,并提供了一些基本的功能,可以通过简单的配置即可使用。
第三方中间件
Express 社区提供了许多第三方中间件,这些中间件可以用于增强 Express 应用的功能。以下是一些常用的第三方中间件:
body-parser
用于解析请求体,支持 JSON、URL 编码和多部分数据。
npm install body-parser
使用方法:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/data', (req, res) => {
console.log(req.body); // 访问 JSON 或 URL 编码数据
res.send('Data received successfully.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
helmet
提供了一系列 HTTP 头的设置,帮助提高 Express 应用的安全性。
npm install helmet
使用方法:
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
compression
用于压缩响应体,减小传输数据的大小。
npm install compression
使用方法:
const express = require('express');
const compression = require('compression');
const app = express();
app.use(compression());
app.get('/', (req, res) => {
res.send('Compressed response.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
morgan
用于记录 HTTP 请求的日志。
npm install morgan
使用方法:
const express = require('express');
const morgan = require('morgan');
const app = express();
app.use(morgan('combined'));
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
这只是一小部分可用的第三方中间件。根据应用需求,你可以选择并安装适合的中间件来增强 Express 应用的功能。
Express路由
all
方法用于匹配所有 HTTP 动词(GET、POST、PUT、DELETE 和 OPTIONS)。
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000
app.all('/*', (req, res) => {
res.send('all')
})
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
路由路径
路由路径也可以是字符串模式。可用部分正则表达式语法来定义端点的模式。以下是所涉及的正则表达式(注意,连字符( -)和点(.)在字符串路径中解释为字面量,不能做为正则表达式)
- 路径中
?
用于匹配路径中包含一个或多个字符的路径。
const express = require('express')
const app = express()
app.get('/us?er', (req, res) => {
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`)
})
请求下面接口都可以请求通:
http://localhost:3000/uer
http://localhost:3000/user
- 路径中
+
用于匹配路径中包含多个字符的路径。
const express = require('express')
const app = express()
app.get('/us+er', (req, res) => {
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen()
只要请求下面的路径都可以请求通
http://localhost:3000/user
http://localhost:3000/ussser
http://localhost:3000/usssser
- 路径中
*
可以替换为任意字符串
const express = require('express')
const app = express()
app.get('/us+er', (req, res) => {
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen()
只要请求下面的路径都可以请求通
http://localhost:3000/ussssser
http://localhost:3000/usABCer
路由参数
路由参数是指在路径中使用冒号(:)来定义的部分。
const express = require('express')
const app = express()
app.get('/user/:id', (req, res) => {
console.log(req.params)
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen()
请求下面接口都可以请求通:
http://localhost:3000/user/123 // 输出 { id: '123' }
http://localhost:3000/user/abc // 输出 { id: 'abc' }
也可以设置多个路由参数
const express = require('express')
const app = express()
app.get('/user/:id/:name', (req, res) => {
console.log(req.params)
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen()
请求下面接口都可以请求通:
http://localhost:3000/user/123/abc // 输出 { id: '123', name: 'abc' }
http://localhost:3000/user/abc/123 // 输出 { id: 'abc', name: '123' }
链式路由
链式路由是指在一个路由中定义另一个路由,并在该路由中定义其它的路由。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.send(`${req.url}`)
}).post('/login', (req, res) => {
res.send(`${req.url}`)
})
const PORT = process.env.PORT || 3000
app.listen()
响应方法
响应方法用于向客户端发送响应,同时也支持链式调用。
res.send()
方法用于发送字符串。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.send('Hello, World!')
})
const PORT = process.env.PORT || 3000
app.listen()
res.download()
方法用于下载文件。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.download('path/to/file')
})
const PORT = process.env.PORT || 3000
app.listen()
res.json()
方法用于发送 JSON 数据。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.json({
name: 'John Doe',
age: 30
})
})
const PORT = process.env.PORT || 3000
app.listen()
res.end()
方法用于结束响应。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.end('Hello, World!')
})
const PORT = process.env.PORT || 3000
app.listen()
res.redirect()
方法用于重定向到另一个 URL。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.redirect('/login')
})
const PORT = process.env.PORT || 3000
app.listen()
res.render()
方法用于渲染模板。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.render('index', {
title: 'Hello, World!'
})
})
const PORT = process.env.PORT || 3000
app.listen()
res.sendStatus()
方法用于设置响应状态码。
const express = require('express')
const app = express()
app.get('/user', (req, res) => {
res.sendStatus(200)
})
const PORT = process.env.PORT || 3000
app.listen()