Express 的使用
1. 什么是 Express?有什么用?
说明
Express 是基于 Node.js 内置 http 模块扩展的一个 Web 开发框架。是一个 第三方包 ,可以极大提升开发效率。
2. Express 基本用法
说明
在这里安装体验的是 express@4.17.1 版本
1. 快速搭建一个 Web 服务器
点击查看 简易服务器代码
const express = require('express')
const app = express()
app.listen(80, () => {
console.log('server is running at http://localhost')
})
2. 监听客户端 请求方法 和 请求路径
说明
- 处理 post 请求:app.post(url, callback)
- 处理 get 请求:app.get(url, callback)
- put, delete...更多方法语法相同
- 其中:
- url 是地址。
- callback 是处理函数,在匹配到对应的 请求方法 和 请求路径 后就会执行。
点击查看 路由处理案例
const express = require('express')
const app = express()
// 1. 当客户端用 get 请求 http://localhost/getUser 这个地址时匹配
app.get('/getUser', (req, res) => {
// req 是请求对象, res 是响应对象
// res.send() 方法用于做出响应
res.send('get')
})
// 2. 当客户端用 post 请求 http://localhost/getUser 这个地址时匹配
app.post('/getUser', (req, res) => {
// res.send() 方法用于做出响应
res.send('post')
})
app.listen(80, () => {
console.log('server is running at http://localhost')
})
3. 获取 和 发送 参数
说明
使用 res.query 和 res.params 来接收参数
点击查看 参数处理案例
const express = require('express')
const app = express()
// 当客户端用 get 请求 http://localhost/getUser?id=1&name=tgx 时匹配
app.get('/getUser', (req, res) => {
// 1. req.query 默认是空对象,接收地址栏的 查询参数
// 此时 req.query 是个对象 { id: '1', name: 'tgx' }
res.send(`查询参数是:${req.query}`)
})
// 当客户端用 post 请求 http://localhost/getUser/5/tgx 时匹配
app.post('/getUser/:uid/:uname', (req, res) => {
// 2. res.params 默认是空对象,接收地址栏的 动态参数
// 此时 req.params 是个对象 { uid: '5', uname: 'tgx }
res.send(`动态参数是:${req.params}`)
})
app.listen(80, () => {
console.log('server is running at http://localhost')
})
4. 托管静态资源
说明
- 使用 app.use(express.static('文件夹')) 来托管静态资源
- 可以多次使用该方法托管(但是如果存在同名资源,优先使用前方的目录)
点击查看 具体案例
const express = require('express')
const app = express()
// 假设 demo 是个文件夹,里面有 index.html, index.css, index.js 三个文件
// 托管后 就可以直接访问 http://localhost/index.html
app.use(express.static('./demo'))
app.listen(80, () => {
console.log('server is running at http://localhost')
})
点击查看 加了前缀的案例
const express = require('express')
const app = express()
// 假设 demo 是个文件夹,里面有 index.html, index.css, index.js 三个文件
// 托管后, 现在要加个前缀, 要访问 http://localhost/demo/index.html
app.use('/demo', express.static('./demo'))
app.listen(80, () => {
console.log('server is running at http://localhost')
})
3. Express 后端路由
概念
- 路由:指的是一种 对应关系
- 前端路由:指 hash 地址 与 组件 的对应关系
- 后端路由:指 请求方式、请求地址 与 处理函数 的对应关系
1. express 中路由的基本用法
说明
express 中一个路由包含 3 个部分
- 请求方式
- 请求地址
- 处理函数
例如:app.get('/getUser', callback) 就是一个路由,其中:
- get 是 请求方式
- /getUser 是 请求地址
- callback 是 处理函数(回调函数)
express 中的路由会从上到下依次匹配,完全匹配到 请求方法、请求地址 后才会执行 回调函数
2. express 中的模块化路由
说明
- 项目中路由应该使用模块化管理,而不是 挂载到 实例 app 上
- app.use() 方法,是用来注册中间件的
- app.use() 方法,如果加了前缀注册路由,请求时,路由前也要加这个前缀,例如:
- 假设服务地址是 http://localhost
- 定义一个路由 router.get('/user/list', (req, res) => {})
- 注册这个路由 app.use(router),则访问 http://localhost/user/list
- 注册这个路由 app.use('/api', router),则访问 http://localhost/api/user/list
点击查看 路由模块
// 使用 router.js模块 来集中管理路由
const express = require('express')
// 创建 路由实例 用来管理路由
const router = express.Router()
// 挂载第一个路由
router.get('/user/list', (req, res) => {})
// 挂载第二个路由
router.post('/home', (req, res) => {})
// 挂载......
module.exports = router
点击查看 如何注册路由模块
const express = require('express')
const app = express()
// 引入并注册 路由模块
const router = require('./router.js')
app.use(router)
app.listen(80, () => {
console.log('server is running at http://localhost')
})
4. Express 中间件
概念
中间件:是指 业务处理的中间环节。后端在接收到前端的请求数据后,要经过一系列的 中间处理环节,最后再把数据返回给前端,而中间这些处理环节就是 中间件
1. 中间件具体是什么?
- 中间件的本质就是 处理函数,与路由处理函数相比,中间件会多出一个 next 参数,且中间件内部必须调用 next() 这个参数(放行函数)
2. 中间件的特性
所有 中间件 按顺序依次从上往下执行,直到最后一个中间件走完了,才会匹配到对应的 路由
所有 中间件 共享同一份 req 和 res
全局中间件:使用 app.use() 或 router.use() 单独注册 的中间件
局部中间件:这种中间件不需要 app.use() 单独注册,而是放在 路由地址 和 路由函数 之间
点击查看 局部中间件用法
// 定义中间件 const mw1 = (req, res, next) => { console.log('中间件 mw1') next() } const mw2 = (req, res, next) => { console.log('中间件 mw2') next() } // 两种写法都可以: // 1. 路由中直接插入,这个 mw1, mw2 就是 局部中间件 app.use('/user', mw1, mw2, (req, res) => {}) // 2. 路由中放入数组插入,这个 mw1, mw2 就是 局部中间件 app.use('/user', [mw1, mw2], (req, res) => {})
3. 中间件的分类
中间件分 5 类
- 应用级别 的中间件:绑在 app.use() 上
- 路由级别 的中间件:绑在 router.use() 上
- 错误级别 的中间件:放在所有 路由 之后
- Express 内置 的中间件
- 第三方 中间件
3.1 应用级别 的中间件
指的是上文的写法,绑在 app.use() 上
3.2 路由级别 的中间件
指的是上文的写法,绑在 router.use() 上
3.3 错误级别 的中间件
说明
放在所有 路由中间件 之后,用来防止某个错误导致服务器崩溃
点击查看 错误级别 中间件
const express = require('express')
const app = express()
// 路由中间件
app.use('/', (req, res) => {})
// 错误中间件 必须 放在所有路由中间件之后,才能捕获错误
app.use((err, req, res, next) => {
console.log('发生了错误' + err.message)
res.send('服务器发生了错误' + err.message)
})
app.listen(80)
3.4 Express 内置 的中间件
说明
- 自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件,极大的提高了 Express 项目的开发效率和体验
- express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
- express.json 解析 JSON 格式的请求体数据(仅在 4.16.0+ 版本中可用)
- express.urlencoded 解析 固定表单格式的请求体数据(仅在 4.16.0+ 版本中可用)
- express.urlencoded 只能解析 application/x-www-form-urlencoded 格式的表单数据
点击查看 express.json 中间件 示例
const express = require('express')
const app = express()
// 需要配置在所有路由之前
// 使用 内置中间件 express.json() 解析客户端发送的请求体,并挂载到 req.body 上
app.use(express.json())
// 第二个中间件
app.use((req, res, next) => {
// 默认 req.body 接收的 json 请求体是 undefined
// 经过 express.json 内置中间件 之后,就能在 req.body 拿到客户端发的 json 内容
console.log(req.body)
res.send('ok')
})
// 路由中间件
app.use('/', (req, res) => {})
app.listen(80)
点击查看 express.urlencoded 中间件 示例
const express = require('express')
const app = express()
// 需要配置在所有路由之前
app.use(express.json()) // 处理 json 请求体
app.use(express.urlencoded({ extended: false })) // 处理 URL-encoded 格式请求体
// 第二个中间件
app.use((req, res, next) => {
// 经过 express.urlencoded 内置中间件 之后,
// 就能在 req.body 拿到客户端发的表单键值对 URL-encoded 格式内容
console.log(req.body)
res.send('ok')
})
// 路由中间件
app.use('/', (req, res) => {})
app.listen(80)
3.5 第三方 中间件
说明
第三方 中间件 是指从 npm 仓库下载的中间件,也可以是自己写的 自定义 中间件。
这里用到了一个 querystring 模块,用来处理字符串,是 node.js 内置模块,与 fs, path 一样
点击查看 自定的中间件 模块
// customBodyParser.js 文件
const qs = require('querystring')
// 自定义一个处理数据的中间件
const customBodyParser = (req, res, next) => {
// 1. 当客户端发送数据时触发 data 事件,监听并拼接客户端发来的数据
let str = ''
req.on('data', chunk => {
// 数据是分片发送的,可能需要多次接收
str += chunk
})
// 2. 当数据发送完成时触发 end 事件
req.on('end', () => {
// qs.parse 方法 可以把字符串解析为对象
req.body = qs.parse(str)
})
next()
}
module.exports = customBodyParser
点击查看 如何使用自定的中间件
const express = require('express')
const customBodyParser = require('./customBodyParser.js')
const app = express()
// 注册自定义的中间件
app.use(customBodyParser)
app.post('/user', (req, res) => {
res.send(req.body)
})
app.listen(80, () => {
console.log('server is running at http://localhost')
})