Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架。
原生的 http 模块在某些方面表现不足以应对我们的开发需求,所以我们就需要使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码更统一。
- 丰富的 API 支持,强大而灵活的中间件特性
- Express 不对 Node.js 已有的特性进行二次抽象,只是在它之上扩展了 Web 应用所需的基本功能
- 内部使用还是 http 模块
- 有很多流行框架基于 Express
安装
npm install --save express
使用
express 提供一些函数
- app.listen ```javascript const http = require(‘http’);
const express = require(‘express’);
const app = express(); // 返回一个 requestListener 处理器
app.listen(3000); // 相当于 // const server = hhtp.createServer(app); // server.listen(3000);
<a name="KJEZC"></a>
# 中间件
通过中间件对整个处理请求函数增加对应的方法,即把不同对应处理的函数分配到各个中间件中。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1753568/1617242127111-78173a68-10ee-40af-a270-f51acbcfcf9d.png#height=521&id=TOHYJ&margin=%5Bobject%20Object%5D&name=image.png&originHeight=521&originWidth=296&originalType=binary&ratio=1&size=260260&status=done&style=none&width=296)
<a name="CqQOs"></a>
## 中间件工作原理
app.use([path,] callback [, callback...])
中间件的回调函数
- 一般响应回调为三个以下或以下
- function(req, res)
- function(req, res, next)
- 错误处理为四个参数 function(err, req, res, next)
err 为错误信息<br />req 请求对象,继承自 http.IncomingMessage<br />res 响应对象,继承自 http.ServerResponse
- res.send express 的响应函数 res 参数除了可以原生使用 write 等 http 原生写响应,也可以使用 send 方法简化响应体
- res.redirect express 提供用于重定向
```javascript
res.redirect('/');
// 相当于
res.statusCode = 302;
res.setHeader('Location', '/');
- res.sendFile 返回响应文件
res.status() 指定发送状态码
// 如 404 页面
app.use((req, res, next) => {
res.status(404).send('<h1>页面走丢了!</h1>');
});
next
next() 往后匹配下一个中间件
- next(‘route’) 往后匹配当前中间件堆栈中的下一个
next(x) x为任何除字符串
'route'
外,会视当前请求错误,将路过所有剩余无错误处理路由和中间件函数app.use 使用中间件处理各种请求
app.post
- app.get
- app.delete
这些都是一个内置的中间件
这些要完全匹配path
app.use((req, res, next) => {
console.log('在中间件中');
next(); // 往下流
});
多个中间件函数
app.get('/', (req, res, next) => {}, (req, res, next) => {});
中间件堆栈
const cb1 = (req, res, next) => {};
const cb2 = (req, res, next) => {};
app.get('/', [cb1, cb2]);
中间件链式
app.get('/', (req, res) => {
res.send(`get`)
}).post('/', (req, res) => {
res.send(`post`)
}).put('/', (req, res) => {
res.send(`put`)
}).delete('/', (req, res) => {
res.send(`delete`)
})
中间件 path 过滤响应与参数
使用 path 控制响应的内容,支持 字符串或正则,可以使用 :params 设置参数
app.get('/', (req, res, next) => { // 在没有匹配到的默认响应
console.log('这个中间件永远都会执行');
next();
});
app.get('/add-product', (req, res, next) => { // 在 path 为 '/' 之前增加
res.send('<h1>添加产品页面</h1>');
});
app.get('/', (req, res, next) => { // 在没有匹配到的默认响应
res.send('<h1>你好,Express!</h1>');
});
app.get('/:id', (req, res, next) => {
console.log(req.params.id);
});
// path 字符串
// 可以用 ? + {} 等正则量词
app.get('/a(bc)?d', (req, res, next) => {
});
app.get('/ab+', (req, res, next) => {
});
app.get('/a{1,4}', (req, res, next) => {
});
// 可以使用 . - 来分隔参数
app.get('/:id1.:id2', (req, res, next) => {
console.log(req.params.id1);
console.log(req.params.id2);
});
// 可以使用 . - 来分隔参数
app.get('/:id1-:id2', (req, res, next) => {
console.log(req.params.id1);
console.log(req.params.id2);
});
// 可以使用 . - 来分隔参数
app.get('/:id1-:id2', (req, res, next) => {
console.log(req.params.id1);
console.log(req.params.id2);
});
// 可以用 (正则) 为参数指定类型,注意字符串要用 \ 转意
app.get('/:id1(\\d+), (req, res, next) => {
console.log(req.params.id1);
console.log(req.params.id2);
});
// 使用正则匹配
app.get(/a/) , (req, res, next) => {
});
app.get(/^bad.*fly$/) , (req, res, next) => {
});
内置中间件
express.json()
express.urlencoded()
app.use(express.json()); // 处理请求体 raw 为 json 的参数
app.use(express.urlencoded()); // 处理请求体 x-www-form-urlencoded 的参数
app.get('/', function(req, res, next) {
console.log(req.body);
})
外置中间件
body-parser
用于解析body请求体的解析器
npm install --save body-parser
bodyParser.urlencoded() 返回一个中间件函数
const bodyParser = require('body-parser');
app.use(bodyParaser.urlencoded({extended:false})); // 不去处理非标准的请求
:::info express v4 版本其实已经对 body-parser 相关的封装到 express 内置中间件,所以现在也很少使用 body-parser :::
cookie-parser 解析 cookie 数据
cors 跨域
compression 压缩 HTTP 响应
morgan 请求日志
…
其他中间件可以访问:
路由
使用express.Router() 可以分拆业务逻辑, 返回中间件函数
admin.js
const express = require('express');
const router = express.Router();
router.get('/add-product', (req, res, next) => {
res.send('<form action="/product" method="POST"><input type="text" name="message" /><button="submit">发送</button></form>');
});
router.post('/product', (req,res, next) => {
res.redirect('/');
});
module.exporets = router;
在app.js中, 路径过滤
const adminRoutes = require('./routes/admin');
// 在path中加入'/admin'进行路径过滤,即访问时要/admin/add-product才能访问到
app.use('/admin', adminRoutes);
静态文件提供
express.static()
app.use(express.static('./public'));
模板引擎
npm install --save ejs pug express-handlebars
配置模板引擎
app.set('view engine', 'pug'); // 配置要使用的引擎
app.set('view', './view'); // 配置模板位置
使用模板
route.get('/', (req, res, next) => {
res.render('模板文件名', {data:'住模板注入数据'});
}
ejs
pug
handlebars
const expressHbs = require('express-handles');
app.engine('handlebars', expressHbs({layoutDir: 'views/layouts', defaultLayout: 'main-layout', extname: 'hbs'})); // 要先注册一个模板引擎