官网传送门

基于 Node.js 平台,快速、开放、极简的 Web 开发框架

Express 是用于快速创建服务器的第三方模块。

1. Express 初体验

1.1 基本使用

安装 Express:

npm install express

创建服务器,监听客户端请求,并返回内容:

使用 npx nodemon 运行

const express = require('express')
// 创建 web 服务器
const app = express()
// 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
  res.send({ name: 'zs', age: 20, gender: '男'
 })
})
app.post('/user', (req, res) => {
  res.send('请求成功')})app.get('/', (req, res) => {
  // 通过 req.query 可以获取到客户端发送过来的查询参数
  console.log(req.query)
  res.send(req.query)
})
// 这里的 :id 是一个动态的参数
app.get('/user/:ids/:username', (req, res) => {
  // req.params 是动态匹配到的 URL 参数,默认是一个空对象
  console.log(req.params)
  res.send(req.params)
})
app.listen(80, () => {
  console.log('express server running at <http://127.0.0.1>')
})

1.1.1 把内容响应给客户端

res.send()

app.get('/user',(req,res)=>{
    res.send({name:'lhd',age:'19'})
})

1.1.2 获取 URL 中携带的查询参数

req.query

app.get('/',(req,res)=>{
    console.log(req.query)
})

1.1.3 获取 URL 中的动态参数

通过 req.params 对象,可以访问到 URL 中,通过 :匹配到的动态参数

// 访问 <http://127.0.0.1/user/1874>
app.get('/user/:id',(req,res)=>{
    res.send(req.params) // 返回 {id:'1874'}
})
// 访问 <http://127.0.0.1/user/1874/lhd>
app.get('/user/:id/:name',(req,res)=>{
    res.send(req.params) // 返回 {id:'1874',name:'lhd'}
})

1.2 托管静态资源

app.use(express.static('public'))
app.use(express.static('files'))
app.use('/bruce', express.static('bruce'))
/*可直接访问 public, files 目录下的静态资源http://localhost:3000/images/bg.jpg
<http://localhost:3000/css/style.css>
<http://localhost:3000/js/login.js>
通过带有 /bruce 前缀的地址访问 bruce 目录下的文件http://localhost:8080/bruce/images/logo.png*/

2. Express 路由

在 Express 中,路由指的是客户端的请求与服务器处理函数之间的映射关系。

Express 中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数。

// METHOD:请求方式,PATH:请求路径,HANDLER:处理函数
app.METHOD(PATH,HANDLER)

2.1 监听 GET 请求

// req:请求对象(包含了与请求相关的属性和方法)
// res:响应对象(包含了与响应相关的属性和方法)
app.get('请求url',function(req,res){
    // 处理函数
})

2.2 监听 POST 请求

// req:请求对象(包含了与请求相关的属性和方法)
// res:响应对象(包含了与响应相关的属性和方法)
app.post('请求url',function(req,res){
    // 处理函数
})

2.3 创建路由模块:

为了方便对路由进行模块化管理,Express 不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。

步骤:

router.js:

const express = require('express')
// router.jsconst express = require('express')
// 创建路由对象
const router = express.Router()
// 挂载具体路由
router.get('/user/list', (req, res) => {
  res.send('Get user list.')
})
router.post('/user/add', (req, res) => {
  res.send('Add new user.')
})
// 向外导出路由对象
module.exports = router

注册路由模块:

module.js:使用 router.js 中的路由

const express = require('express')
const router = require('./router')
const app = express()
// 注册路由模块,添加访问前缀,前缀可以省略
app.use('/api', router)
app.listen(80, () => {
  console.log('<http://127.0.0.1>')
})

3. Express 中间件

请求到达 Express 服务器之后,可连续调用多个中间件,从而对这次请求进行预处理。和vue的路由守卫一样,next()代表放行

中间件注意事项;

3.1 全局中间件

const express = require('express')
const app = express()
// 定义第一个全局中间件
app.use((req, res, next) => {
  console.log('调用了第1个全局中间件')
  next()
})
// 定义第二个全局中间件
app.use((req, res, next) => {
  console.log('调用了第2个全局中间件')
  next()
})
app.get('/user', (req, res) => {
  res.send('User page.')
})
app.listen(80, () => {
  console.log('<http://127.0.0.1>')
})

3.1.1 next() 函数

next() 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或者路由。

3.1.2 定义中间件函数

const express = require("express")
const app = express()

// mw 指向的就是一个中间件函数
const mw = function(req.res,next){
    console.log('这是个简单的中间件函数')
    next()
}

app.listen(80, ()=>{
	console.log("DDD")
}

3.1.3 全局生效的中间件

只要有请求到达服务器,必先经过mw中间件函数处理。相对于vue前置守卫,拦截器

// mw 指向的就是一个中间件函数
const mw = function(req.res,next){
    console.log('这是个简单的中间件函数')
    next()
}

// 全局生效的中间件
app.use(mw)

app.get("/", (req, res) => {
 res.send("hhh")
}) 

简化

app.use(function(req,res,next){
    console.log('这是给简单的中间件函数')
    next()
})

3.1.4 多个中间件

按注册顺序排,且必须在路由上方。多个中间件共享req和res。

// 完整示例
const express = require('express')
const app = express()

app.use((req, res, next) => {
  console.log('第一个中间件')
  next()
})
app.use((req, res, next) => {
  console.log('第二个中间件')
  next()
})

app.get('/', (req, res) => {
  res.send({ info: '请求了服务器', method: req.method })
})

app.listen(80, () => {
  console.log('<http://127.0.0.1>')
})

3.2 局部中间件

const express = require('express')
const app = express()
// 定义中间件函数
const mw1 = (req, res, next) => {
	console.log('调用了第一个局部生效的中间件')
  next()}
const mw2 = (req, res, next) => {
  console.log('调用了第二个局部生效的中间件')
  next()
}
// 两种定义局部中间件的方式
app.get('/hello', mw2, mw1, (req, res) => res.send('hello page.'))
app.get('/about', [mw1, mw2], (req, res) => res.send('about page.'))
app.get('/user', (req, res) => res.send('User page.'))
app.listen(80, function () {
  console.log('Express server running at <http://127.0.0.1>')
})

3.2.1 局部生效的中间件

不用 app.use() 定义的中间件,叫做局部生效的中间件

const mw = function(req,res,next){
    console.log('中间件函数')
    next()
}
app.get('/',mw,(req,res)=>{
    res.send('Hellow World')
})
app.get('/user',(req,res)=>{
    res.send('Hellow World')
})

3.2.2 多个局部中间件

// mw1与mw2 为中间件函数,两种方式等价
app.get('/',mw1,mw2,(req,res)=>{ xxx })
app.get('/',[mw1,mw2],(req,res)=>{ xxx })

3.3 中间件的作用

多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。

// 示例:每个请求都需要获取时间
app.use((req, res, next) => {
  req.startTime = Date.now()
  next()
})
app.get('/user',(req,res)=>{
    res.send('time:'+req.startTime)
})

3.4 中间件分类

3.4.1 应用级别的中间件

// 应用级别中间件起(全局中间件)
app.use((req, res, next) => {
  next()
})
// 应用级别中间件(局部中间件)
app.get('/user', mw1 ,(req,res)=>{
    res.send('time:'+req.startTime)
})

3.4.2 路由级别的中间件

const app = express()
const router = express.Router()
router.use(function (req, res, next) {
  console.log(1)
  next()
})
app.use('/', router)

3.4.3 错误级别的中间件

const express = require('express')
const app = express()
app.get('/', (req, res) => {
  throw new Error('服务器内部发生了错误!')
  res.send('Home page.')
})
// 定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err, req, res, next) => {
  console.log('发生了错误!' + err.message)
  res.send('Error:' + err.message)
})
app.listen(80, function () {
  console.log('Express server running at <http://127.0.0.1>')
})

3.4.4 Express 内置中间件

自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件,极大的提高了 Express 项目的开发效率和体验: