Express

一、初识Express

1.1 Express 简介

1.1.1 什么是Express简介

  • Express是基于Node.js平台,快速、开放、极简的Web开发框架
  • Express的作用和Node.js内置 的http模块类似,是专门用来创建Web服务器的
  • 本质:就是一个npm上的第三方包,提供快速创建Web服务器的便捷方法
  • 官网地址 http://www.expressjs.com.cn/

1.1.2 进一步理解Express

  • 使用Node.js提供的原生http模块也可以创建Web服务器
  • Express是基于内置的http模块进一步封装出来的,提高开发效率
  • http模块与Express的关系 类似于Web API与JQuery的关系

1.1.3 Express能做什么

使用Express能够方便快捷的创建Web网站的服务器 或 API接口的服务器

  • Web网站服务器:专门对外提供Web网页资源的服务器
  • API接口服务器:专门对外提供API接口的服务器

1.2 Express的基本使用

1.2.1 安装

  • 在项目所处的目录中,运行
npm i express@4.17.1

1.2.2 创建基本的Web服务器

//1.导入express
const express=require("express")
//2.创建web服务器
const app=express()
//3.启动服务器
app.listen(80,()=>{
console.log('http://127.0.0.1:80')
})

1.2.3 监听GET请求

//参数1 客户端请求的URL地址
//参数2 请求对应的处理函数
//req:请求对象(包含了与请求相关的属性和方法)
//res:响应对象(包含了与响应相关的属性和方法)
app.get('请求的url',(req,res)=>{

})

1.2.4 监听POST请求

//参数1 客户端请求的URL地址
//参数2 请求对应的处理函数
//req:请求对象(包含了与请求相关的属性和方法)
//res:响应对象(包含了与响应相关的属性和方法)
app.post('请求的url',(req,res)=>{

})

1.2.5 把内容响应给客户端

res.send()方法

app.get('/user',(req,res)=>{
	//向客户端 发送JSON对象
	res.send({name:'张三'})
})
app.post('/user',(req,res)=>{
	//向客户端发送文本内容
	res.send('请求成功')
})

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

通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数

app.get('/',(req,res)=>{
	//req.query 默认是一个空对象
	//客户端使用?name=zs&age=20 查询字符串,发送到服务器的参数
	//req.query.name req.query.age
	console.log(req.query)
})

1.2.7 获取URL中的动态参数

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

//注意:这里的:id 是一个动态的参数
app.get('/user/:id/:name', (req, res) => {
    //req.params 是动态匹配到的url参数  默认是一个空对象
    console.log('req', req.params);
    res.send(req.params)
})

在这里插入图片描述

1.3 托管静态资源

1.3.1 express.static()

非常方便的创建一个静态资源服务器

  • express在指定的目录中查找文件,并对外提供资源的访问路径
  • 存放静态文件的目录名不会出现在URL中
//将public目录下的图片,css文件 js文件对外开放访问
app.use(express.static('public'))

在这里插入图片描述

1.3.2 托管多个静态资源目录

//http://127.0.0.1:3030/index.html 访问地址
app.use( express.static(path.join(__dirname, './file')))
//http://127.0.0.1:3030/index.html 访问地址
app.use( express.static(path.join(__dirname, './clock')))

1.3.3 挂载路径前缀

在托管的静态资源访问路径之前,挂载路径前缀

//http://127.0.0.1:3030/abc/index.html 访问地址
app.use('/abc', express.static(path.join(__dirname, './file')))

//http://127.0.0.1:3030/clock/index.html 访问地址
app.use('/clock', express.static(path.join(__dirname, './clock')))

1.4 nodemon

1.4.1为什么使用nodemon

在这里插入图片描述

1.4.2 安装nodemon

npm install nodemon -g

1.4.3 使用nodemon

nodemon index.js

二、Express路由

2.1 路由的概念

2.1.1 什么是路由

广义来讲,路由就是 映射关系

在这里插入图片描述

2.1.2 Express 中的路由

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

在这里插入图片描述

2.1.3 Express中的路由例子

//挂载路由
app.get('/', (req, res) => {
    res.send('hello word')
})
app.post('/', (req, res) => {
    res.send('Post Request')
})

2.1.5 路由的匹配过程

在这里插入图片描述

2.2 路由的使用

2.2.1 最简单的用法

在express中,把路由挂载到app上

const express = require("express");
const app = express();
//挂载路由
app.get('/', (req, res) => {
    res.send('hello word')
})
app.post('/', (req, res) => {
    res.send('Post Request')
})
app.listen(3001, (req, res) => {
    console.log('http://127.0.0.1:3001');

})

2.2.2 模块化路由

在这里插入图片描述

2.2.3 创建路由模块

//这是路由模块
//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

2.2.4 注册路由模块

const express = require("express");
const app = express();
//1.导入路由模块
const router = require("./05-router")

//2.注册路由模块
//'/api' 挂载访问前缀
app.use('/api', router)
//注意点
//app.use==>用来注册全局中间件

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

2.2.5 为路由模块添加前缀

//'/api' 挂载访问前缀
app.use('/api', router)

三、Express中间件

3.1 中间件的概念

3.1.1 什么是中间件

中间件(Middleware),特指业务流程的中间处理环节

3.1.2 现实生活中的例子

在这里插入图片描述

3.1.3 Express中间件的调用流程

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

在这里插入图片描述

3.1.4 Express中间件的格式

Express 的中间件,本质上就是一个 function 处理函数

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

在这里插入图片描述

3.1.5 next函数的作用

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

在这里插入图片描述

3.2 Express中间件的初体验

3.2.1 定义中间件函数

//定义一个最简单的中间件函数
const mw = function (req, res, next) {
    console.log('这是最简单的中间件函数');
    //把流转关系 转交给下一个中间件或路由
    next()
}
//将mw 注册为全局生效的中间件
app.use(mw)

//定义全局中间件的简化形式
app.use((req, res, next) => {
    console.log('这是最简单的中间件函数');
    next()
})

3.2.2 全局生效的中间件

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

通过调用 app.use(中间件函数),即可定义一个全局生效的中间件

//将mw 注册为全局生效的中间件
app.use(mw)

3.2.3 定义全局中间件的简化形式

//定义一个最简单的中间件函数
const mw = function (req, res, next) {
    console.log('这是最简单的中间件函数');
    //把流转关系 转交给下一个中间件或路由
    next()
}

3.2.4 中间件的作用

在这里插入图片描述

3.2.5 定义多个全局中间件

可以使用 app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用

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

3.2.6 局部生效的中间件

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

/定义中间件函数
const mw1 = function (req, res, next) {
    console.log('调用了局部生效中间件');
    next()
}
//局部生效的中间件
app.get('/', mw1, (req, res) => {
    console.log('请求了/路由');
    res.send('///')
})
app.get('/user', (req, res) => {
    console.log('请求了/user路由');
    res.send('/user')

})

3.2.7 定义多个局部中间件

app.get('/', mw1, mw2, (req, res) => {
    console.log('请求了/路由');
    res.send('///')
})

3.2.8 了解中间件的5个使用注意事项

在这里插入图片描述

3.3 中间件的分类

3.3.1 应用级别的中间件

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

3.3.2 路由级别的中间件

绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件。

  • Router 实例是一个完整的中间件和路由系统
    在这里插入图片描述

3.3.3 错误级别的中间件

  • 作用 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
  • 格式 错误级别中间件的 function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next)。
  • 错误级别的中间件必须注册在所有路由之后
const express = require("express");

const app = express();

//定义路由
app.get('/', (req, res) => {
    //1.1 人为制造错误
    throw new Error('服务器内部发生了错误')
    res.send('Home page')
})

//定义错误级别的中间件  捕获整个项目的异常错误 从而防止程序的崩溃
app.use((err, req, res, next) => {
    console.log('发生了错误', err.message);
    res.send('Error:' + err.message)
})

app.listen(3002, () => {

    console.log('http://127.0.0.1:3002');
})

3.3.4 Express内置的中间件

express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)

express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)

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

const express = require("express");

const app = express();

//注意:除了错误级别的中间件 其他的中间件 都必须在路由之前进行配置
//通过 express.json()中间件 解析表单中的JSON格式的数据
app.use(express.json())

//定义路由
app.post('/', (req, res) => {
    //在服务器,可以使用req.body这个属性 来接收客户端发送过来的请求体数据
    //默认情况下 如果不配置解析表单数据的中间件时,则req.body默认等于undefined
    console.log(req.body);
    res.send('Home page')
})

//通过express.urlencoded()来解析表单中url-encoded格式的数据
app.use(express.urlencoded({ extended: false }))
app.post('/book', (req, res) => {
    //在服务器,可以使用req.body这个属性 获取json格式表单的数据和URL-encoded 格式的数据
    console.log(req.body);
    res.send('ok')
})
app.listen(3002, () => {

    console.log('http://127.0.0.1:3002');
})

postm 下的json格式

在这里插入图片描述

postmen 下的URL-encoded 格式

在这里插入图片描述

3.3.5 第三方的中间件

非 Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件

在这里插入图片描述

3.4 自定义中间件

3.4.1 需求描述与实现步骤

在这里插入图片描述

3.4.2 定义中间件

在这里插入图片描述

3.4.3 监听req的data事件

在这里插入图片描述

3.4.4 监听req的end事件

在这里插入图片描述

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

在这里插入图片描述

3.4.6 将解析出来的数据对象挂载为req.body

在这里插入图片描述

3.4.7 将自定义中间件封装为模块

在这里插入图片描述

自定义中间件js部分

//1.导入express模块
const express = require("express");
//一、导入自定义封装的中间件模块
const customBodyParser = require("./15-custom-body-parser.js")
//导入处理 querystring 模块
const qs = require("querystring")

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

//使用中间件  解析表单数据的中间件
//二、将自定义的中间件函数 注册为全局可用的中间件
app.use(customBodyParser)

//路由
app.post('/user', (req, res) => {

    res.send(req.body)
})
app.get('/user', (req, res) => {
    res.send('ok')
})
//3.启动服务器
app.listen(3033, () => {
    console.log('启动成功');
})

模块部分

//1.导入express模块
const express = require("express");

//导入处理 querystring 模块
const qs = require("querystring")

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

const bodyParser = (req, res, next) => {
    //定义中间件的业务逻辑
    //1.定义一个str字符串 专门用来存储客户端发送过来的请求体数据
    let str = ''

    //2.监听req的data事件
    req.on('data', (chunk) => {
        str += chunk
    })
    //3.监听req对象的end事件(请求体发送完毕后自动触发)
    req.on('end', () => {
        //打印完整的请求体数据
        console.log(str)
        //把字符串格式的请求体数据,解析成对象格式
        const body = qs.parse(str)
        console.log('body', body);
        //挂载为req的属性
        req.body = body
        //调用next函数
        next()
    })
}

//路由
app.post('/user', (req, res) => {

    res.send(req.body)
})
app.get('/user', (req, res) => {
    res.send('ok')
})
//3.启动服务器
app.listen(3030, () => {
    console.log('启动成功');
})
module.exports = bodyParser

四、使用Express写接口

4.1 创建基本的服务器

  • 如果要获取 URL-encoded 格式的请求体数据,必须配置中间件 app.use(express.urlencoded({ extended: false }))
//1.1导入express 模块
const express = require("express");

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

//3.1 配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false }))

//2.1 导入路由模块
const router = require("./17-apiRouter.js")
//2.2 把路由模块注册到app 上 /api为前缀(访问路径)
app.use('/api', router)

//1.3启动服务器
app.listen(3001, () => {
    console.log('http://127.0.0.1:3001');

})

4.2 创建API路由模块

//导入express模块
const express = require("express");

const router = express.Router();

//挂载对应的路由
//编写GET接口
router.get('/get', (req, res) => {
    //1.获取到客户端通过查询字符串,发送到服务器的数据
    const query = req.query
    //2.调用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
    })
})
//暴漏出去 供外界使用
module.exports = router;

4.5 CORS跨域资源共享

4.5.1 接口的跨域问题

解决接口跨域问题的方案主要有两种:

  • ① CORS(主流的解决方案,推荐使用)
  • ② JSONP(有缺陷的解决方案:只支持 GET 请求)

4.5.2 使用cors中间件解决跨域问题

在这里插入图片描述

4.5.3 什么是CORS

在这里插入图片描述

4.5.4 CORS的注意事项

  • ① CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
  • ② CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服 务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

4.5.5 CORS响应头部

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5.6 CORS请求的分类

根据请求方式和请求头的不同,可以将 CORS 的请求分为简单请求 预检请求

4.5.7 简单请求

同时满足以下两大条件的请求,就属于简单请求:

  • ① 请求方式:GET、POST、HEAD 三者之一
  • ② HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、 Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-formurlencoded、multipart/form-data、text/plain)

4.5.8 预检请求

只要符合以下任何一个条件的请求,都需要进行预检请求:

  • ① 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
  • ② 请求头中包含自定义头部字段
  • ③ 向服务器发送了 application/json 格式的数据
    在这里插入图片描述

4.5.9 简单请求和预检请求的区别

  • 简单请求的特点:客户端与服务器之间只会发生一次请求。
  • 预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求

4.6 JSONP接口

4.6.1 回顾JSONP的概念和特点

概念 浏览器端通过 script 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP。

  • 特点 只支持get请求,不属于真正的ajax请求,没有使用XMLHttpRequest

4.6.2 创建JSONP接口的注意事项

在这里插入图片描述

4.6.3 实现JSONP接口的步骤

在这里插入图片描述

4.6.4 具体代码

//5 必须在配置cors 中间件之前 配置JSONP的接口
app.get('/api/jsonp', (req, res) => {
    //定义JSONP具体的实现过程
    //5.1 获取客户端发送过来的回调函数的名字
    const funcName = req.query.callback
    //5.2 得到要通过JSONP形式发送到客户端的数据
    const data = { name: 'zs', age: 23 }
    //5.3 根据前两步得到的数据 拼接出一个函数调用的字符串
    const Str = `${funcName}${JSON.stringify(data)}`
    //5.4 把上一步拼接得到的字符串 响应给客户端的<script>标签进行解析执行
    res.send(Str)
})

4.6.5 在网页中使用jquery发起JSONP请求

 //为jsonp绑定点击事件处理函数
        $('#JSONP').on('click', () => {
            $.ajax({
                method: 'GET',
                url: 'http://127.0.0.1/api/jsonp',
                dataType: 'jsonp',
                success: function (res) {
                    console.log('res', res);
                }

            })
        })

版权声明:本文为Gik99原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/Gik99/article/details/129124122