Node.js(四)

Node.js 第四天

一、Express插件

1、什么是 Express

基于 Node.js 平台,快速、开放、极简的 Web 开发框架, 本质上就是一个 npm 的第三方包, 给我们提供了快速创建 web 服务器的方法

2、Express的应用场景

  1. 开发 Web 网站服务器

  2. API 接口服务器

3、安装 Express

在项目的根目录下, 执行命令: npm i express@4.17.1

4、Express使用

  1. 基本使用及对get、post请求进行监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 引入包
const express = require('express');

// 创建一个服务器实例
const app = express();

// 监听用户的get请求
app.get('/userinfo', (req, res) => {
// 使用send方法向客户端响应一个json字符串
res.send({ name: 'xh', age: 12, height: 155 })
});

// 注意:/ 表示我们的根路径
app.get('/', (req, res) => {
// 使用send方法向客户端响应一个json字符串
res.send({ name: 'xh', age: 12, height: 155 })
});

// 监听用户post请求
app.post('/login', (req, res) => {
res.send('登录成功!')
})
// 启动服务
app.listen(3006, () => {
console.log('启动服务成功:http://localhost:3006');
})
  1. 获取动态参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 引入包
const express = require('express');
// 创建web服务器实例
const app = express();
// id标明这是一个动态查询参数,实际请求的时候不需要加:
app.get('/my/article/deletecate/:id/:name', (req, res) => {
// 多个动态参数以/:拼接
//获取url上的动态参数,结果是一个对象
console.log(req.params.id, req.params.name);
res.send(req.params);
});
// 启动服务,监听端口
app.listen(3006, () => {
console.log('服务运行:http://localhost:3006/my/article/deletecate/20/zs');
})
  1. 托管动态资源并添加资源前缀

    注意:优化为绝对地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 引入包
const express = require('express');
const path = require('path');
// 创建web服务器实例
const app = express();

// 托管assets文件夹下所有的静态资源 express.static()
// 为静态资源的路径添加一个公共的资源前缀
app.use('/public', express.static(path.join(__dirname,'./assets')));

// 启动服务,监听端口
app.listen(3006, () => {
console.log('服务运行:http://localhost:3006/public');
})

二、nodemon包

每次修改 node.js 服务端代码都需要重新启动服务, 比较繁琐, nodemon 插件可以实时监测文件的动态变化,

并当文件内容变化时自动重启服务

  • 全局安装:

    npm i -g nodemon

  • 使用方法:

    nodemon index.js

三、路由

1、定义

路由在广义上理解就是指一种映射关系, 在 node.js 中指的是客户端的请求和服务端处理函数的映射关系,Express 路由包括 3 部分: 请求的 URL, 请求的类型, 处理函数

2、定义路由方法

app.Method(URL, handler)

  • 创建路由实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express = require('express');

// 生成一个路由实例对象
const router = express.Router();

// 再向路由实例对象上挂载
router.get('/', (req, res) => {
res.send('hello!')
});
router.get('/api', (req, res) => {
res.send('world')
});
router.post('/api', (req, res) => {
res.send('hello!123')
});
//注意要暴露出去
module.exports = router;
  • 调用路由实例:
1
2
3
4
5
6
7
8
9
10
11
12
const express = require('express');
const router = require('./10-创建路由模块');//为穿建路由的自定义模块

// 创建web服务器实例
const app = express();

// 添加第一个参数: 表示请求路由url的公共前缀
app.use('/my', router);

app.listen(3006, () => {
console.log('运行成功:http://localhost:3006/my');
})

四、中间件

1、什么是中间件?

​ 泛指业务流程的中间处理环节, Express 的中间件即是指响应数据的中间环节, 本质上就是一个处理函数

2、中间件的参数列表

​ 包含 req 请求对象, res 响应对象 和 next 回调函数, 注意路由处理函数中没有 next 参数

3、next 参数的作用

用来实现多个中间件连续调用的关键, 一个中间件函数内必须调用 next() 将控制权传递给下一个中间件功能, 否则该请求将被挂起。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义一个中间件函数
const middleware = (req, res, next) => {
console.log('正在处理请求');
// 调用next() 表示当前中间件处理函数, 移交给下一个中间件或路由处理
next();
};
//使用中间件
app.use(middleware);
//可以简写为:
app.use((req, res, next) => {
console.log('执行第二个中间件');
next();
});

4、中间件的范围

  • 全局中间件: 任何请求到达服务器之后都会触发的中间件
  • 局部中间件: 只有匹配当前路由的请求到达服务器才会触发的中间件
1
2
3
4
5
6
7
8
9
10
// 定义一个局部中间件函数
const mw = (req, res, next) => {
console.log('使用了局部中间件');
next();
};

// 注册局部中间件(只对匹配当前路由的请求生效),放在注册路由参数的第二个参数位置
app.get('/', mw, (req, res) => {
res.send("hello")
});
  • 多个局部生效的中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 注册第一个中间件
const mw1 = (req, res, next) => {
req.name = 'zs';
req.pwd = 'asd455';
res.age = '20';
console.log('执行第一个中间件');
next();
}

// 注册第二个中间件
const mw2 = (req, res, next) => {
console.log('执行第二个中间件');
next();
}
//或者直接逗号隔开
app.get('/', [mw1, mw2], (req, res) => {
console.log(req.name, req.pwd, res.age);
res.send("hello")
});

5、中间件的注意事项

  1. 全局中间件的注册要放在路由定义之前

  2. 对于一个客户端的发送过来的请求, 可以调用多个中间件进行处理

  3. 中间件的处理函数中一定要有 next() 调用

  4. next 函数之后不用再写和业务无关的代码

  5. 多个中间件之间共享 req 和 res 对象

6、中间件的分类

  1. 应用层中间件

  2. 路由级中间件 router(url,中间件,fn())

  3. 错误处理中间件 (err,req,res,fn())

    ​ 注意: 一定要放在所有路由之后

    1
    2
    3
    4
    5
    6
    7
    // 错误级别中间件一定要放在末尾
    app.use((err, req, res, next) => {
    if (err) {
    console.log('错误信息:' + err.message);
    res.send({ status: 1, message: err.message })
    }
    })
  4. 内置中间件

  5. 第三方中间件

7、内置中间件

  • express.static() 快速托管静态资源的中间件

  • express.json() 解析客户端传递的 json 格式的请求体数据,处理post表单提交的application/json 格式的数据

  • express.urlencoded() 解析客户端传递的 urlencoded 编码形式的请求体数据,处理post表单提交的application/x-www-form-urlencode 格式的数据

1
2
3
4
5
// 处理post表单提交的application/json 格式的数据
app.use(express.json());

// 处理post表单提交的application/x-www-form-urlencode 格式的数据
app.use(express.urlencoded({ extended: false }))

8、第三方中间件

非 Express 内置给我们的, 而是由第三方个人或公司开发的中间件, 我们可以先下载再配置来进行使用

示例: 使用 body-parse 这个中间件来解析请求体的数据

  1. 运行命令下载 npm i body-parse

  2. 使用 require() 方法引入

  3. 使用 app.use() 方法注册

9、自定义中间件

实现步骤:

  1. 定义全局中间件

  2. 监听 req 的 data 事件

  3. 监听 req 的 end 事件

  4. 使用 querystring 模块解析请求体数据

  5. 把解析后的数据挂载到 req.body 上

  • qs.stringify()把对象转换成查询字符串

  • qs.parse()把查询字符串转换为对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 引入内置的querystring
const qs = require('querystring');
const bodyParser = (req, res, next) => {

let str = '';

// 监听req的data事件(post表单提交的数据量很多,分批发送)
req.on('data', (chunk) => {
// chunk每次发送到服务器的数据片段
console.log(chunk); //默认是utf-8二进制
str += chunk;
});
// 监听req的end事件(服务器已经接收到客户端发送的完整数据)
req.on('end', () => {
console.log(str); //获取请求体的数据,键值对的字符串
const type = req.get('Content-Type');
console.log(type);
if (type === 'application/json') {
// 把转换后的参数对象挂载到req.body上,共享给构面的中间件或路由使用
req.body = JSON.parse(str);
} else if (type === 'application/x-www-form-urlencoded') {
// 把转换后的参数对象挂载到req.body上,共享给构面的中间件或路由使用
req.body = qs.parse(str);
}
next()
});

};
// 向外暴露
module.exports = bodyParser;

10、cors概念了解

  1. 定义

    (Cross-Origin Resource Sharing) 跨域资源共享, 由一系列的 HTTP 响应头组成, 这些响应头决定了浏览器是否阻止前端 js 代码发出跨域请求。

  2. CORS 的响应头部

    (1) Access-Control-Allow-Origin: url/* 指定了允许访问该资源的url

    (2) Access-Control-Allow-Headers: a, b, c 指定了允许发送哪些请求头

    (3) Access-Control-Allow-Methods: GET, POST 指定了允许发送何种类型的请求

  3. cors 请求的分类

    简单请求: 请求方式为 GET/POST/HEAD 之一; 无自定义请求头字段

    预检请求: 请求方式不为 GET/POST/HEAD 之一; 存在自定义请求头字段; 发送了 application/json 格式数据

    浏览器会先发送一个 OPTIONS 请求进行预检, 以确认服务器是否允许该实际请求, 完成后再发送真正的请求

11、案列:express写接口

  • 在文件一中编写接口路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const express = require('express');
const router = express.Router();

// 编写一个get接口,返回的数据格式同大事件接口
router.get('/get', (req, res) => {
// 获取请求参数对象:req.query;获取动态参数:req.params
const data = req.query;
console.log(data);
res.send({
status: 0,
message: '获取数据成功!',
data
})
});

// 编写一个post接口
router.post('/post', (req, res) => {
const data = req.body;
console.log(data);
res.send({
status: 0,
message: '提交数据成功!',
data
})
});

// 编写一个delete接口
router.delete('/delete', (req, res) => {

res.send({
status: 0,
message: '删除数据成功!',

})
});
module.exports = router;
  • 文件二中写接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const express = require('express');
//解决跨域问题
const cors = require('cors');
const app = express();
// 引入路由模块
const router = require('./19-apiRouter');//指文件一的相对路径

// 在路由之前配置中间件
app.use(express.urlencoded({ extended: false }));
app.use(express.json());

// 优先创建jsonp接口
app.get('/api/jsonp', (req, res) => {
console.log(req.query.callback); //客户端发送的回调函数
// 响应函数调用
res.send(`
${ req.query.callback}({name:'zs',age:10})
`)
})

// 在路由之前 注册cors中间件
app.use(cors());

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

// 页面查找不到
app.use((req, res, next) => {
res.send('404 页面找不到了');
next()
})

//编写错误级别的中间件
app.use((err, req, res, next) => {
if (err) {
res.send({
status: 1,
message: err.message
})
};
next();
})

app.listen(3006, () => {
console.log('服务运行在:http://localhost:3006');
});

运行文件二,在postman中进行测试


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!