目录
express简介:
express是什么?
express能做什么?
express的安装与使用
express 的基本使用:
监听GET请求:
托管静态资源:
nodemon:
express路由:
路由的概念:
路由匹配的过程:
路由的使用:
创建路由模块:
注册路由模块:
express中间件:
定义多个全局中间件:
定义局部生效的中间件:
了解中间件的5个使用注意事项:
中间件的分类:
自定义中间件:
使用express写接口:
创建基本的服务器:
创建api路由模块:
编写GET接口:
编写Post接口:
CORS跨域:
什么是cors:
使用cors中间件解决跨域问题:
cors使用注意事项:
结语:
express是基于node.js平台创建的一个快速,开发,极简的web开发框架。
可以通过express框架创建web服务器通过使用express内置封装的http模块可进一步提高开发效率
对于前端程序员来说,最常见的两种服务器就是:
通过使用express框架可以方便,快速的创建web网站服务器和api接口服务器
在项目所处的目录中,运行如下终端命令,即可将express安装在项目中
npm i [email protected]
使用express框架创建基本服务器
//1.导入express
const express = require('express')
//2.创建web服务器
const app = express()
//3.启动web服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1')
})
使用 app.get()方法 ,可以监听客户端GET请求:
//参数1:客户端请求的url地址
//参数2:请求对应的处理函数
//req:请求对象(包含了与请求属性相关的属性与方法)
//res:响应对象(包含了与响应对象相关的属性与方法)
app.get('请求url',function(req,res){/*处理函数*/})
其中的res为响应对象
通过res.send()方法,可以将处理好的内容,发送给客户端
app.get('/user',(req,res)=>{
//向客户发送json请求
res.send({name:'zs',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
//向客户端发送文本内容
res.send('请求帮助')
})
其中req为请求对象
通过req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器端的参数:
app.get('/', (req, res) => {
//通过req.query可以获取到客户端发送过来的查询参数
//注意:在默认情况下,req.query是一个空对象
//客户端使用?name=zs&age=20这种查询字符串形式,发送到服务器参数
//可以通过req.query对象访问到,例如:
//req.query.name req.query.age
console.log(req.query)
res.send(req.query)
})
通过使用req.params对象,可以访问到URL中,通过:匹配到的动态参数
//url地址中,我们开业通过:参数名的形式,匹配动态参数值
app.get('user/:id',(req,res)=>{
//req.params默认是一个空对象
//里面存放这通过:动态匹配到的参数值
console.log(req.params)
})
express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以非常方便地创建一个静态资源服务器
静态服务器:可以直接访问目录下的图片,css文件,js文件等等
app.use(express.static('文件名'))
注:在托管多个静态资源目录时要注意express.static()会根据目录的添加顺序查找所需的文件
基于node.js编写一个网站应用的时候,传统的方式,是运行node app.js命令,来启动项目。这样做的坏处是:当代码被修改之后,需要手动重启项目
使用 nodemon命令,使用nodemon app.js来启动项目,这样好处是:代码被修改之后,会被nodemon监听到,从而实现自动重启项目的效果
node app.js
//将上面的终端命令,替换为下面的终端命令,即可实现自动重启项目的效果
nodemon app.js
路由是一种映射关系:在express中,指得是客户端请求与服务器处理函数之间的映射关系
express中的路由分为三部分组成,分别是请求的类型,请求的URL地址,处理函数
app.METHOD(PATH,HANDLER)
例:
//匹配GET请求,且请求URL地址为/
app.get('/',function(req,res){
res.send('Hello World!')
})
//匹配post请求,且请求URL地址为/
app.post('/',function(req,res){
res.send('Got a POST request')
})
每次一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功后,才会调用对应的处理函数。在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的URL同时匹配成功,则express会将这次请求,转交给对应的function处理函数进行处理
在express中使用路由最简单的方式,就是把路由器挂载到APP上
const express=require('express')
//创建web服务器,命名为app
const app= express()
//挂载路由
app.get('/',(req,res)=>{
res.send('hello world')
})
app.post('/',(req,res)=>{
res.send('Post Request.')
})
//启动web服务器
app.listen(80,()=>{
console.log('http://127.0.0.1')
})
为了方便对路由进行模块化的管理,将路由抽离为单独的模块。将路由抽离为单独模块步骤如下:
// 这是路由模块
// 1. 导入 express
const express = require('express')
// 2. 创建路由对象
const router = express.Router()
// 3. 挂载具体的路由
router.get('/user/list', (req, res) => {
res.send('Get user list.')
})//获取挂载用户列表的路由
router.post('/user/add', (req, res) => {
res.send('Add new user.')
})//获取添加用户的路由
// 4. 向外导出路由对象
module.exports = router
// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块
app.use(router)
在express中一个请求到达express服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
可以使用app.use()连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
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')
})
不使用app.use()定以的中间件,叫做局部生效的中间件:
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// 1. 定义中间件函数
const mw1 = (req, res, next) => {
console.log('调用了局部生效的中间件')
next()
}
// 2. 创建路由
app.get('/', mw1, (req, res) => {
res.send('Home page.')
})
app.get('/user', (req, res) => {
res.send('User page.')
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
console.log('Express server running at http://127.0.0.1')
})
express中间件可分为5大部分:
1:应用级别的中间件
通过使用app.use app.get() app.post(),绑定到app实例的中间件
2:路由级别的中间件
绑定到express.Ruter()实例上的中间件叫做路由级别的中间件。它的用法和应用级别的中间件没有区别,只不过是绑定子router实例上,而应用级别的中间件时绑定在app.use()实例上。
3:错误级别的中间件
错误级别中间件的作用:专门用来抓获整个项目发生的异常错误,从而防止项目异常奔溃问题、
app.use((err, req, res, next) => {
console.log('发生了错误!' + err.message)
res.send('Error:' + err.message)
})
注:错误级别的中间件需要放在所有路由之后
4:express内置中间件
express中内置了3个常用的中间件,极大的提高了express的开发效率和体验
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// 注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置
// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())
// 通过 express.urlencoded() 这个中间件,来解析 表单中的 url-encoded 格式的数据
app.use(express.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
// 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
// 默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined
console.log(req.body)
res.send('ok')
})
app.post('/book', (req, res) => {
// 在服务器端,可以通过 req,body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据
console.log(req.body)
res.send('ok')
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
console.log('Express server running at http://127.0.0.1')
})
5:第三方的中间件
非express官方的中间件,由第三方开发出来的中间件,叫做第三方中间件
例:解析表单的中间件 body-parser 中间件
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// 1. 导入解析表单数据的中间件 body-parser
const parser = require('body-parser')
// 2. 使用 app.use() 注册中间件
app.use(parser.urlencoded({ extended: false }))
// app.use(express.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
// 如果没有配置任何解析表单数据的中间件,则 req.body 默认等于 undefined
console.log(req.body)
res.send('ok')
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
console.log('Express server running at http://127.0.0.1')
})
自己手动模拟一个类似于express.urlencoded 这样的中间件,来解析post提交到服务器的表单数据
1:定义中间件
app.use((req, res, next) => {
// 定义中间件具体的业务逻辑
})
2:监听req的data事件
‘在中间件中,需要监听req对象的data事件,来获取客户端发送到服务器的数据
如果数据量较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以data事件可能触发多次,每一次触发date事件,,获取的数据只是部分数据,需要手动对接收到的数据进行拼接
// 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据
let str = "";
// 2. 监听 req 的 data 事件 data数据量大,无法完全接收需要进行切割一部分进行接收
req.on("data", (chunk) => {
str += chunk;
});
3:监听req的end事件
当请求体数据接收完毕之后,会触发req的end事件
因此,在我们可以在req的end事件中,拿到并处理完整请求数据体
// 3. 监听 req 的 end 事件(请求体发送完毕后自动触发)
req.on("end", () => {
// 在 str 中存放的是完整的请求体数据
// console.log(str)
// TODO: 把字符串格式的请求体数据,解析成对象格式
const body = qs.parse(str);
req.body = body;
// console.log(body);
next();
});
4:使用querystring模块解析请求体数据
node.js内置了querystring模块,专门用来处理查询字符串,通过这个模块提供的parse()函数,可以把查询字符串,解析成对象的格式
// 导入 Node.js 内置的 querystring 模块,专门用来处理查询字符串
const qs = require("query // console.log(str)
// TODO: 把字符串格式的请求体数据,解析成对象格式
const body = qs.parse(str);string");
5:将解析出来的数据对象挂载为req.body
中间件之间及路由之间会共享一份req和res。因此可以将解析出来的数据挂载为req.body的自定义属性上
req.on("end", () => {
// 在 str 中存放的是完整的请求体数据
// console.log(str)
// TODO: 把字符串格式的请求体数据,解析成对象格式
const body = qs.parse(str);
req.body = body;
// console.log(body);
next();
});
6:将自定义中间件封装为模块
为优化代码的结构,可以将自定义的中间件函数,封装为独立的模块
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// 1. 导入自己封装的中间件模块
const customBodyParser = require('./14.custom-body-parser')
// 2. 将自定义的中间件函数,注册为全局可用的中间件
app.use(customBodyParser)
app.post('/user', (req, res) => {
res.send(req.body)
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
console.log('Express server running at http://127.0.0.1')
})
导入express包,创建服务器实例对象
// 导入 express
const express = require('express')
// 创建服务器实例
const app = express()
// 启动服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1')
})
const express = require('express')
const router = express.Router()
// 在这里挂载对应的路由
module.exports = router
使用router.get()进行封装
router.get('/get', (req, res) => {
// 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
const query = req.query
// 调用 res.send() 方法,向客户端响应处理的结果
res.send({
status: 0, // 0 表示处理成功,1 表示处理失败
msg: 'GET 请求成功!', // 状态的描述
data: query, // 需要响应给客户端的数据
})
})
// 定义 POST 接口
router.post('/post', (req, res) => {
// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据需要配置全局中间件
const body = req.body
// 调用 res.send() 方法,向客户端响应结果
res.send({
status: 0,
msg: 'POST 请求成功!',
data: body,
})
})
接口的跨域问题:刚才编写的GET和POST请求,存在一个很严重的问题:不支持跨域请求。
解决接口跨域问题的方案主要有两种:
1.CORS(主流的方案,推荐使用)
2.JSONP(有缺陷的解决方案:只支持GET请求)
cors是express的中间件,通过安装与配置cors中间件可以方便的解决跨域问题
注:需要在路由之前进行配置
cors内部详细内容在跨源资源共享(CORS) - HTTP | MDN (mozilla.org)
博主 node.js专栏正在持续更新中,关注博主订阅专栏学习Node不迷路!