Node进阶(二)

109 阅读5分钟

引入Express

为了增加服务器端的开发效率,我们需要引入服务端框架Express,Express是基于node内置http模块进一步封装的。

首先需要npm下载express模块,启动本地服务

// 引入express包
const express = require('express')
const app = express()
// 启动服务器,监听8089端口
app.listen(8089, (req, res) => {
    console.log('server running at 127.0.0.1:8089');
})

建立接口,返回数据

我们可以创建接口,并根据请求方式(GET/POST),返回数据。

GET请求

// 监听get请求
// 参数一:客户端请求的url
// 参数二:包含请求体req和响应体res
app.get('/demo', (req, res) => {
    // send方法,可以向客户端返回JSON对象
    res.send({
        name: 'asdf',
        age: 30,
        gendaer: '女'
    })
})

用postman可以看到他返回了我们设置的JSON对象

image.png

POST请求

// 监听post请求
app.post('/demo', (req, res) => {
    // send方法,也以向客户端返回字符串
    res.send('这里这里')
})

同样返回成功!

image.png

前文中提到过end方法用来响应数据,那么它和send有什么区别呢? www.cnblogs.com/yaya666/p/1…

获取URL中携带的查询参数(query)

app.get('/demo', (req, res) => {
    // 将请求的参数相应回客户端
    res.send(req.query)
})

可以看到客户端发出携带的查询参数后,服务端完整地接收到,并返回给客户端

image.png

获取URL中动态参数(params)

// 可匹配多个动态参数
app.get('/demo/:name/:id', (req, res) => {
    // 设置请求头的编码格式,防止乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    // 返回请求的参数,默认返回空对象
    res.send(req.params)
})

可以看到客户端发出请求后,服务端接收到了demo后的参数,依次命名为name和id,并返回给客户端,为了防止中文乱码,设置了编码格式

image.png

向外暴露静态资源

// 使用use注册全局中间件,向外暴露静态资源文件
app.use(express.static('./txttxt'))

设置好后,客户端就可以直接访问暴露位置内的服务端文件了

image.png

image.png

自定义并注册路由模块

为了代码的解耦,我们需要将路由功能单独封装成一个文件,方便使用。

router.js

// 引入express包
const express = require('express')
// 创建函数
const router = express.Router()
// 监听get请求
router.get('/demo/:name/:id', (req, res) => {
    // 设置请求头的编码格式,防止乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    console.log(req.params); 
    // 返回请求的参数
    res.send(req.params)
})
// 监听post请求
router.post('/demo', (req, res) => {
    // send方法,也以向客户端返回字符串
    res.send(req.query)
})
// 导出路由模块
module.exports = router

main.js

// 引入express包
const express = require('express')
// 创建函数
const app = express()
// 引入自定义路由
const router = require('./router')
// 注册路由
app.use(router)

// 启动服务器,监听8089端口
app.listen(8089, (req, res) => {
    console.log('server running at 127.0.0.1:8089');
})

给路由添加统一请求前缀

为方便接口的管理,需要给需要分类的接口增加统一的前缀,只需要在注册路由时增加一个入参

// 注册路由
app.use('/api', router)

这样在router内的接口就会统一增加前缀api

image.png

Express中间件

类似于vue中的路由守卫,服务端中间件可以用来拦截客户端请求,使用next方法后才能执行后面的路由

全局中间件

// 引入express包
const express = require('express')
// 创建函数
const app = express()
// 启动服务器,监听8089端口
app.listen(8089, (req, res) => {
    console.log('server running at 127.0.0.1:8089');
})
// 服务端路由守卫中间件,在形参中存在第三个参数,即为中间件
const mw = (req, res, next) => {
    console.log('你经过了我这里!');
    // 拦截请求,返回信息
    // res.send('请求失败')
    
    // 放行,转交给下一个中间件或路由
    next()
}
// 注册中间件为全局
app.use(mw)
// 监听get请求
app.get('/mw/:name/:id', (req, res) => {
    // 设置请求头的编码格式,防止乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    console.log(req.params); 
    // 返回请求的参数
    res.send(req.params)
})

使用use方法挂在全局组件,由于是全局定义的中间件,所以可以在返回的请求/响应体中挂载共有变量,共享给后面的路由

const mw = (req, res, next) => {
    // 挂载变量供路由使用
    const time = Date.now()
    req.startTime = time
    console.log('你经过了我这里!')
    // 放行,转交给下一个中间件或路由
    next()
}

对于注册多个全局组件,可以多次使用use方法,全局组件按照声明顺序,依次执行。

局部中间件

在get/post请求的中间形参中可增加中间件,此中间件只对当前方法生效

const mw = (req, res, next) => {
    // 挂载变量供路由使用
    const time = Date.now()
    req.startTime = time
    console.log('你经过了我这里!')
    // 拦截请求,返回信息
    // res.send('请求失败')
    // 放行,转交给下一个中间件或路由
    next()
}
// 监听get请求,引入中间件mw
app.get('/mw/:name/:id', mw, (req, res) => {
    // 设置请求头的编码格式,防止乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    console.log(req.startTime);
    // 返回请求的参数
    res.send(req.params)
})

使用多个局部中间件,可依次在接口参数('/mw/:name/:id')与回调函数中增加形参,以逗号分隔,也可以使用 [ ] 数组形式包裹

官方将中间件分为三大类

1. 应用级中间件

绑定在express实例上的中间件

2. 路由级别中间件

绑定在Router方法上的中间件

3. 错误级别中间件

在中间件的function回调函数中,必须有4个形参,(err, req, res, next)

错误级中间件专门用来捕获整个项目中的异常错误,防止项目异常导致崩溃的问腿。

注意:错误级中间件需要放置在所有路由之后!

app.get('/mwno/:name/:id', (req, res) => {
    throw new Error('服务器内部错误')
})
// 全局注册错误级中间件
app.use((err, req, res, next) => {
    res.send(err.message)
})

image.png

上面代码及效果图中可以看到,当有接口返回错误时,增加错误级中间件可以在保持程序不崩溃的前提下,将错误返回给客户端。

解析客户端GET请求中的JSON数据

路由之前加入全局注册方法express.json()

// express.json()中间件,用于解析表单中JSON格式的数据
app.use(express.json())

req请求体中的body属性可以接收到客户端发来的数据

app.get('/mw/:name/:id', mw, (req, res) => {
    // 设置请求头的编码格式,防止乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    // 请求体中的body,可以看到客户端发来的数据
    console.log(req.body);
    // 返回请求的参数
    res.send(req.params)
})