文章目录
- 五、Express中间件
- 六.中间件的初体验
- 七.中间件的分类
- 八.使用Express写接口
- 九.跨域问题
- 十、配置文件上传
- 十一、安装mongose连接mongodb
一、什么是Express
- 基于 Node.js 平台,快速、开放、极简的 Web 开发框架
1.1、学习目标
- 能够使用express.static() 快速托管静态资源
- 能够使用express路由精简项目结构
- 能够使用常见的express中间件
- 能够使用express创建API接口
- 能够在express中**启用cors跨域
1.2.express能做什么
- **Web网站服务器:**专门对外提供Web网页资源的服务器
- **API接口服务器:**专门对外提供API接口服务器
二、express的基本使用
2.1、安装:npm i express
2.2、创建基本的web服务器(在src/app.js)
- 导入express
- 创建web服务器
- 调用app.listen(端口号,回调函数),启动服务器
2.3、监听get请求
- 通过app.get()方法监听get请求
// 4.监听客户端的get和post请
app.get('/user',(req,res)=>{
// 调用express提供的res.send()方法,向客户端响应一个json对象
res.send({name:'lq',age:22,sex:'男'})
})
2.4、监听post请求
- 通过app.post()方法监听post请求
app.post('/user',(req,res)=>{
// 调用express提供的res.send()方法,向客户端响应一个文本
res.send('请求成功')
})
2.5、res.send()方法
1. 通过res.send()方法可以把处理好的内容,发给客户端
2.6、获取URL中携带的查询参数(req.query)
- 通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
代码演示:
app.get('/',(req,res)=>{
console.log(req.query);
})
结果展示:
2.7、获取URL中动态参数
- 通过req.params对象,可以访问到URL中通过:匹配到的动态参数
代码演示:
const express = require('express')
const app = express()
// 1. 通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
app.get('/user/:id',(req,res)=>{
console.log(req.params);
res.send(req.params)
})
app.listen(80 , (req,res)=>{
console.log('express运行在192.168.0.101');
})
结果展示:
三、托管静态资源(express.static())
3.1、基本使用
- 通过express.static(),我们可以非常方便的创建一个静态资源服务器,例如如下代码就可以将public目录下的图片、css、js文件对外开放
- app.use(express.static(‘public’))
代码演示:
// 通过express.static('文件路径'),我们可以非常方便的创建一个静态资源服务器
app.use(express.static('./src/public'));
结果展示:
3.2、托管多个静态资源目录
1. 多次使用app.use(express.static(‘public’))就可以访问静态资源文件时,express.static()函数会根据目录添加顺序查找所需要的文件**
3.3、挂在路径前缀(必须挂载,不然会跟之前托管的文件起冲突)
- app.use('前缀’express.static(‘public’))
代码演示:
// 通过express.static('访问前缀','文件路径'),我们可以非常方便的创建一个静态资源服务器
app.use(express.static('./src/public'));
// 托管多个静态资源文件夹的时候,需要在路径前加一个前缀,否则会冲突
app.use('/pub',express.static('./src/pub'));
结果展示:
四、Express路由
4.1.路由的概念
-
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
-
Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数
app.method(url,fun)
-
按照定义的先后顺序进行配
-
请求类型和请求的URL同时匹配成功才会调用相应的处理函数
4-2.路由的使用
- 在express中使用路由最简单的方式,就是把路由挂载到app上
4-3.模块化路由
为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到app,上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤:
- 创建路由模块对应的.js文件 src下面创建一个router文件夹
- 调用express.Router()函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用module.exports向外共享路由对象
- 使用app.use0函数注册路由模块
src/router/users.router.js代码演示:
// 1.导入express
const express = require('express')
// 2. 调用express.Router()函数创建路由对象
var router = express.Router()
// 3. 向路由对象上挂载具体的路由
router.get('/user/list',(req,res)=>{
res.send('get挂载成功')
})
router.post('/user/add',(req,res)=>{
res.send('post挂载成功')
})
// 4. 使用module.exports向外共享路由对象
module.exports = router
4-4.注册路由模块
- 导入路由模块
- 使用app.use(模块)
app.js代码演示:
// 1. 导入路由模块
const usersRouter = require('./router/users.router')
// 2. 使用app.use(模块)
app.use(usersRouter)
4-5.为路由添加前缀
app.use('/api',usersRouter)
五、Express中间件
5-1.中间件的概念
- 当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
5-2.中间件的格式
- express的中间件本质上就是一个function处理函数
- 中间件的格式如下
注意:中间件函数的形参列表中,必须包含next参数,而路由处理函数中只包含req和res
5-3.next函数的作用
- next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一一个中间件或路由。
六.中间件的初体验
6-1.定义一个简单的中间件
// 1.定义一个简单的中间件
var mw = function (req, res, next) {
console.log('请求路径是:' + req.url)
next()
}
6-2.全局生效的中间件
- 客户端发起的请求,到达服务器后,都会触发的中间件,叫做全局生效中间件
- app.use(中间件名称)
// 1.定义一个简单的中间件
var mw = function (req, res, next) {
console.log('请求路径是:' + req.url)
next()
}
// 2.使用中间件,中间件的使用必须再挂载路由之前执行,所以必须放在路由挂载之前
app.use(mw)
// 1. 导入路由模块
const usersRouter = require('./router/users.router')
// 2. 使用app.use(模块)
app.use('/api',usersRouter)
当我们访问接口的时候的效果
6-3.简化全局中间件
// 简化版中间件
app.use(function (req, res, next) {
console.log('请求路径是:' + req.url)
next()
})
6-4.中间件的作用
- 多个中间件之间,共享同-份req和res.基于这样的特性,我们可以在上游的中间件中,统-为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
6-5.定义多个全局中间件
- 可以使用app.use0连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用,示例代码如下:
// 简化版中间件
app.use(function (req, res, next) {
console.log('第一个中间件')
next()
})
app.use(function (req, res, next) {
console.log('第二个中间件')
next()
})
app.use(function (req, res, next) {
console.log('第三个中间件')
next()
})
6-6.局部生效的中间件
- 不使用app.use()的中间件就是局部中间件
const express = require('express')
const app = express()
// 定义一个中间
var zjj = function(req,rea,next){
console.log('局部中间件');
next()
}
app.get('/',zjj,(req,res)=>{
res.send('局部中间件')
})
app.post('/user',zjj,(req,res)=>{
res.send('局部中间件')
})
app.listen(80,()=>{
console.log('run in 192.168.0.101');
})
6-7.定义多个局部中间件
app.get('/',zjj1,zjj2,zjj3,(req,res)=>{
res.send('局部中间件')
})
6-8.中间件的五个注意事项
- 中间件要放在路由前面
- 客户端发送请求可以调用多个中间件
- 中间件一定不要忽略next()
- 为了防止代码混乱,写了next()函数后,就不要写额外的代码了
- 连续调用多个中间件,多个中间件之间共享req和res
七.中间件的分类
- 应用级别的中间件
- 路由级别的中间件
- 错误级别的中间件
- Express内置的中间件
- 第三方的中间件
7-1.应用级别的中间件
- 通过app.use()或app.ge()或app.pos(),绑定到app实例上的中间件,叫做应用级别的中间件
7-2.路由级别的中间件
- 绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不
过,应用级别中间件是绑定到app实例上,路由级别中间件绑定到router实例上。
7-3.错误级别的中间件
- 错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
- 格式:错误级别中间件的function 处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)。
代码演示:
const express = require('express')
const app = express()
app.get('/',(req,res)=>{
throw new Error('服务器内部发生错误')
res.send('index')
})
// 定义一个错误中间件
app.use(function(err,req,res,next){
console.log('Error'+err.message);
res.send('Error'+err.message)
next()
})
app.listen(80,()=>{
console.log('run in 192.168.0.101');
})
注意:错误中间件一定要注册到路由的后面
7-4.Express内置的中间件
- express.static快速托管静态资源的内置中间件
- express.json解析JSON格式的请求数据(在4.16.0版本之前不可用)
- express.urlencoded解析URL-encoded/x-www-form-yrlcoded格式的请求数据(在4.16.0版本之前不可用)
7-5.第三方的中间件
- 非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
如何使用第三方中间件body-parser,作用:来解析请求体数据
- npm install body-parser安装中间件
- 使用require导入中间件
- 使用app.use()注册中间件
const express = require('express')
const app = express()
// 1. npm install body-parser安装中间件
// 2. 使用require导入中间件
const parser = require('body-parser')
// 3. 使用app.use()注册中间件
app.use(parser.urlencoded({extend:false}))
app.get('/',(req,res)=>{
res.send('ok')
console.log(req.body);
})
app.listen(80,()=>{
console.log('run in 192.168.0.101');
})
7-6.自定义中间件
例如每次请求判断token是否过期的中间件,或者根据token判断用户对某些路由是否有权限的中间件
八.使用Express写接口
8-1.Express写接口步骤
- 创办基本服务器
const express = require('express')
const app = express()
app.listen(80,()=>{
console.log('run in 192.168.0.101');
})
- 创建API路由模块
const express = require('express')
const router = express.Router()
router.get('/get',(req,res)=>{
})
module.exports = router
- 写GET接口
const express = require('express')
const { appendFile } = require('fs')
const apiRouter = express.Router()
// GET接口
apiRouter.get('/get',(req,res)=>{
// 1.获取到客户端通过查询字符串,发送到服务器的数据
const query = req.query
// 2.调用send()方法,把数据响应给客户端
res.send({
status:0, // 状态0表示成功,1表示失败
msg:'GET请求成功', // 状态描述
data:query // 响应给客户端的具体数据
})
})
module.exports = apiRouter
- 写POST接口
const express = require('express')
const { appendFile } = require('fs')
const apiRouter = express.Router()
// GET接口
apiRouter.get('/get',(req,res)=>{
// 1.获取到客户端通过查询字符串,发送到服务器的数据
const query = req.query
// 2.调用send()方法,把数据响应给客户端
res.send({
status:0, // 状态0表示成功,1表示失败
msg:'GET请求成功', // 状态描述
data:query // 响应给客户端的具体数据
})
})
// POST接口
apiRouter.post('/post',(req,res)=>{
// 1.获取到客户端通过请求体,发送到服务器的urlencoded数据
const body = req.body
// 2.调用send()方法,把数据响应给客户端
res.send({
status:0, // 状态0表示成功,1表示失败
msg:'POST请求成功', // 状态描述
data:body // 响应给客户端的具体数据
})
})
module.exports = apiRouter
- 导入路由模块(服务器上)
// 导入路由模块、
const router = require('./03.get接口')
- 把路由模块注册到app上
// 把路由模块注册到app上
app.use('/api',router)
- 配置解析表单数据的中间件
// 配置解析表单数据的中间件
app.use(express.urlencoded({extended:false}))
8-2.成功编写GET/POST接口
九.跨域问题
9-1.跨域问题演示
- 我们所写的get和post接口不支持跨域请求
9-2.解决跨域问题
- CORS(主流的解决方案)
- jsonp(有缺陷:只能支持get请求)
9-3.使用cors中间件解决跨域问题
- 运行npm i cors 安装中间件
- 在服务器的路由前面导入中间件require(‘cors’)
- 在路由之前调用中间件app.use(cors())
代码演示:
// 在路由前导入使用cors
const cors = require('cors')
app.use(cors())
结果展示:
9-4.什么是cors
- CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。
- 浏览器的同源安全策略默认会阻止网页"跨域”获取资源。但如果接口服务器配置了CORS相关的HTTP响应头,就可以解除浏览器端的跨域访问限制。
注意事项:
- CORS主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。
- CORS在浏览器中有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如: IE10+. Chrome4+、FireFox3.5+).
9-5.cors响应头
9-5-1.cors响应头 - Access-Control-Allow-Origin
//表示与允许来自任何域的请求
res.setHaeder('Access-Control-Allow-Origin','*')
9-5-2.cors响应头 - Access-Control-Allow-Headers
- 默认支持9个请求头:Accept. Accept-Language、 Content-Language. DPR、Downlink. Save-Data. Viewport-Width. Width 、Content-Type (值仅限于text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
//允许客户端额外向服务器发送Content-Type 请求头和 X-Custom-Header请求头
res.setHaeder('Access-Control-Allow-Headers','Content-Type','X-Custom-Header')
9-5-3.cors响应头 - Access-Control-Allow-Methods
- 默认情况下cors仅支持客户端发起GET,POST,HEAD请求
//如果客户端希望通过PUT、DELETE 等方式请求服务器的资源
res.setHaeder('Access-Control-Allow-Methods','POST','GET','HEAD')
//允许所有的HTTP请求方法
res.setHaeder('Access-Control-Allow-Methods','*')
十、配置文件上传
10-1、安装formidable
npm i formidable
10-2、src/router/upload.router.js内容
// 1.导入express
const express = require('express')
const {formidable} = require('formidable')
const path = require('path')
// 2. 调用express.Router()函数创建路由对象
var router = express.Router()
// 3.文件上传接口
router.post('/upload',(req,res)=>{
const upload =formidable({
// 上传地址
uploadDir:path.resolve(__dirname,'../public/img'),
// 文件加上后缀
keepExtensions:true
})
// err:错误信息
// fields:表单数据
// files:文件名
upload.parse(req,(err,fields,files)=>{
if(err){
res.send({
code:400,
msg:'文件上传失败'
})
}else{
res.send({
code:200,
msg:'文件上传成功',
data:files
})
}
})
})
// 4. 使用module.exports向外共享路由对象
module.exports = router
10.3、使用注册路由app.js中
// 1. 导入路由模块
const uploadRouter = require('./router/upload.router')
// 2. 使用app.use(模块)
app.use(uploadRouter)
十一、安装mongose连接mongodb
11-1、安装mongose
npm install mongoose@6.8.0
11-2、创建src/model/db.js
// 1.链接数据库
var mongoose = require('mongoose')
mongoose.set('strictQuery',true)
// 2.链接数据库
mongoose.connect('mongodb://localhost:27017/test').then(() => console.log('链接成功!')).catch(err=>{
console.log('链接失败',err);
})
// 3.暴露连接对象
module.exports = mongoose