Express

Express是基于Node.js凭条,快速、开放、极简的Web开发框架。

Express的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。

是npm第三方包。

安装express

npm i express@4.17.1

创建web服务器

const express = require('express')

const app =express()

app.listen(80,()=>{
    console.log('express server running at http://127.0.0.1')
})

监听get请求,post请求

//监听get请求
//参数1:客户端请求的URL地址
//参数2:请求对应的处理函数
//      req:请求对象
//      res:响应对象
app.get('/user',(req,res)=>{
    //调用express中send方法向客户端响应一个JSON对象
    res.send({name:'zs',age:20,gender:'男'})
})


//监听POST请求
//参数1:客户端请求的URL地址
//参数2:请求对应的处理函数
//      req:请求对象
//      res:响应对象
app.post('/user',(req,res)=>{
    //响应给客户端
    res.send('请求成功')
})

获取URL中携带的查询参数

//获取url中携带的查询参数,通过req.query对象,可以访问到客户端通过查询字符串的行使,发送到服务器的参数
app.get('/',(req,res)=>{
    //req.query默认是一个空对象
    //客户端使用?name=zs&age =20这种查询字符串形式,发送到服务器的参数
    //可以通过req.query对象访问到,例如:
    //req.query.name req.query.age
    console.log(req.query)
})

获取url中的动态参数

//获取URL中的动态参数,通过req.params对象,可以访问到URL中,通过:匹配到的动态参数:
app.get('/user/:id',(req,res)=>{
    //req.params默认是一个空对象
    //里面存放这通过 : 动态匹配到的参数值
    console.log(req.params)
})

托管静态资源

托管多个静态资源目录时,多次调用express.static函数即可

//托管静态资源,express.static()
//通过它,我们可以非常方便地创建一个静态资源服务器
app.use(express.static('public'))
//此时我们可以访问public目录下的所有文件了

例:

此时在网页端加上文件后缀即可访问文件

// 例:
app.use(express.static('./tools'))
app.listen(80,()=>{
    console.log('express server running at ')
})

挂载路径前缀

希望在访问文件之前加上前缀

//挂载路径前缀
app.use('/public',express.static('public'))

nodemon

安装

npm install -g nodemon

使用,nodemon会自动监听代码更改情况,对服务器进行重启

nodemon <文件名> //启动项目

Express路由

路由的概念:指客户端的请求与服务器处理函数之间的一个映射关系。

express中路由分3部分组成,分别是请求的类型、请求的url地址、处理函数,格式如下:

app.METHOD(PATH,HANDLER) //method对应请求的类型,path对应url地址,handler对应处理函数

//例:
app.get('/',function(req,res){
	res.send('hello world')
})

app.post('/',function(req,res){
    res.send('got a post request')
})

路由的匹配过程

每当一个其你去到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才回调用对应的处理函数。

在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的url同时匹配成功,则express会将这次请求,转交给对应的function函数进行处理。

路由的使用

最简单用法,将路由挂载到app实例上

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

模块化路由

将路由抽离为单独的模块

//路由模块化
var router = express.Router() //创建路由对象
//
router.get('/user/list',function (req,res) {
    res.send('Get user list ')
})
//
router.post('/user/add',function (req,res) {
    res.send('add new user')
})
//向外导出路由对象
module.exports = router


//在主程序中
const express = require('express')
const app = express()
const router = require('router.js')
app.use(router)
app.listen(80,function(){
    
})

app.use 用来注册全局中间件的

为路由模块加前缀时

app.use('/api',router)

Express中间件

中间件:特指业务流程的中间处理环节

express中间件的调用流程

当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理

express中间件的格式

express中间件,本质上就是function处理函数,格式如下:

image-20220110155537227

中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res

next函数的作用

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

定义中间件函数

const mw = function (req,res,next) {
    console.log('简单函数')
    //注意:在当前中间件的业务处理完毕后,必须调用next()函数
    //表示把流转关系交给下一个中间件或路由
    next();
}

全局生效的中间件

客户端发起任何请求,到达服务器后,都会触发的中间件,叫做全局生效的中间件。

app.use(mw) //使mw全局生效

中间件的作用

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

//例
app.use((req,res,next)=>{
    const time = Date.now();
    req.startTime= time;
    next();
})
app.get('/',(req,res)=>{
    res.send('Home page' + req.startTime)
})

定义多个全局中间件

连续定义多个全局中间件,当客户端请求到达服务器之后,会按照定义的先后顺序一次进行调用。

局部生效的中间件

const mw1 = function (req,res,next) {
    console.log('这是中间件函数')
    next()
}
//此处mw1是局部生效的中间件,只在当前路由中生效
app.get('/',mw1,function (req,res) {
    res.send('home page')
})

定义多个局部中间件

app.get('/',mw1,mw2,(req,res)=>{
    res.send('home page')
})
//或
app.get('/',[mw1,mw2],(req,res)=>{
    res.send('home page')
})

中间件注意事项:

1、一定要在路由之前注册中间件。

2、一定要在中间件中调用next()函数

3、在next()之后不要添加额外内容

4、多个中间件共享req和res

中间件分类

1、应用级别的中间件(通过app.use()、app.get()、app.post(),绑定到app实例上的中间件)

2、路由级别的中间件(绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定在app实例上,路由级别中间件绑定到router实例上)

例:

const router = express.Router();
router.use(function (req,res,next) {
    console.log('Time:',Date.now())
    next()
})

app.use('/',router)

3、错误级别的中间件(专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题)

错误级别中间件的function中,必须有4个形参(err,req,res,next))注册在所有路由之后

app.get('/',function (req,res) {
    throw new Error('服务器内部发生错误')
    res.send('home page')
})

app.use(function (err,req,res,next) {
    console.log('发生错误'+err.message);
    res.send('Error!'+err.message)
})

4、Express内置的中间件

​ 1、express.static 快速托管静态资源的内置中间件

​ 2、express.json 解析JSON格式的请求体数据(仅在4.16.0版本之后中可用)

​ 3、express.urlencoded 解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0之后版本中可用)

//服务器端可以用req.body接受请求体数据

app.use(express.json())  //将请求体中的JSON数据进行解析,解析之后可以用req.body进行访问

app.use(express.urlencoded({extended:false})) 

5、第三方的中间件(非内置的由第三方开发出来的中间件)

//例如:body-parser解析表单数据的中间件
const parser = require('body-parser')
app.use(parser.urlencoded({extended:false}))

app.post('/user',(req,res)=>{
    console.log(req.body)
    res.send('ok')
})

自定义中间件

//自定义中间件
app.use(function (req,res,next) {
    let str ='';
    req.on('data',(chunk) => {
        str +=chunk;
    })
    req.on('end',()=>{
        const body = qs.parse(str)
        req.body = body;
        console.log(str)
    })
})

//使用querystring模块,专门用来处理查询字符串。通过这个模块提供的parse()函数可以轻松查询字符串,解析成对象的格式

const qs = require('querystring')

const body = qs.parse(str)