1、什么是Express
Express是基于Node.js平台,快速、开放、极简的web开发框架,它的作用和Node.js内置的http模块类似,是专门用来创建web服务器的,Express本质上就是一个npm的第三方包,提供了快速创建web服务器的便捷方法。 Express中文网:https://www.expressjs.com.cn/
2、Express的安装
在项目所处的目录中,运行如下的终端命令,即可将express安装到项目中使用。
npm install express@4.17.1
3、Express的基本使用
3.1 创建基本的web服务器
const express=require('express');
const app=express();
......
app.listen(8089,()=>{
console.log('express server is running at http://127.0.0.1:8089');
})
3.2 配置监听请求
app.get('请求URL',function(req,res){
res.send('get')
})
app.post('请求URL',(req,res)=>{
res.send('post')
})
3.3 响应客户端数据
通过res.send()方法可以把处理好的内容,发送给客户端。
app.get('/user',function(req,res){
res.send({name:'张三',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
res.send('用户信息请求成功')
})
3.4 请求参数处理
(1)获取URL中携带的查询参数: 通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数。
app.get('/user',function(req,res){
console.log(req.query)
})
(2)获取URL中的动态参数: 通过req.params对象,可以访问到URL中通过:匹配到的动态参数
app.get('/user/:name',function(req,res){
console.log(req.params)
res.send(req.params)
})
app.post('/user/:name/:pwd',(req,res)=>{
res.send("post请求")
console.log(req.params)
})
4、Express静态资源处理
4.1 express.static()
express通过提供的函数express.static()。可以方便地创建一个静态资源服务器,将指定目录下的图片、css文件、js文件对外开放。
app.use(express.static('./images'))
注意: Express在指定的静态目录中查找文件,并对外提供资源的访问路径,因此,存放静态文件的目录名不会出现在URL中,例如,上述代码指定public文件夹中的文件对外开放,访问路径如下: http://127.0.0.1:8081/1.jpg
4.2 托管多个静态资源目录
如果要托管多个静态资源目录,需要多次调用express.static()函数。
app.use(express.static('./public'))
app.use(express.static('./files'))
访问静态资源文件时,express.static()函数会根据目录的先后顺序查找所需的文件,如果第一个文件中已经找到,就不会继续再往下进行查找。
4.3 挂载路径前缀
如果希望在托管的静态资源访问路径之前挂载路径的前缀,需要进行如下设置:
app.use('/public',express.static('./images'))
5、Express路由
5.1 什么是Express中的路由
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系,它由三部分组成,分别是请求的类型、请求的URL地址、处理函数。
app.get('/',(req,res)=>{
})
app.post('/user',(req,res)=>{
})
5.2 路由的匹配过程
每当一个请求到达服务器后,需要先经过路由的匹配,只有匹配成功后,才会调用对应的处理函数,在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的URL同时匹配成功,则Express会将这次请求,转交给对应的function函数进行处理。
5.3 路由的使用
5.3.1 简单用法
在Express中使用路由最简单的方法就是将路由挂载到app上。
const express=require('express')
const app=express()
app.get('/',(req,res)=>{
res.send("123")
})
app.post('/user',(req,res)=>{
res.send("345")
})
app.listen(8082,()=>{
console.log("服务已启动")
})
5.3.2 模块化路由
为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。 将路由抽离为单独的模块步骤:
- 创建路由模块对应的.js文件
- 调用express.Router()函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用module.exports向外共享路由的对象
- 使用app.use()函数注册路由模块
const express=require('express')
const router=express.Router()
router.get('/list',(req,res)=>{
res.send("list")
})
router.get('/add',(req,res)=>{
res.send("add")
})
module.exports=router
const express=require('express')
const router=require('./router/router')
const app=express()
app.use(router)
app.listen(8082,()=>{
console.log("启动服务成功")
})
6、Express中间件
6.1 什么是中间件
中间件,特指业务流程的中间处理环节,当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。Express中间件本质上就是一个function处理函数。 中间件的作用: 多个中间件之间共享同一份req和res,基于这样的特性,我们可以在上游的中间件中统一为req或res对象添加自定义的属性或方法,供下游的中间件或者路由进行使用。
6.2 中间件的使用
6.2.1 定义中间件函数
中间件函数的形参列表中,必须包含next函数,而路由处理函数中只包含req和res。 next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
const mv=function(req,res,next){
console.log('这是一个最简单的中间件函数')
next()
}
6.2.2 全局中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。
const express=require('express')
const app=express()
const mv=function(req,res,next){
console.log("我是一个中间件")
next()
}
app.use(mv)
app.get('/',(req,res)=>{
res.send("Hello World")
})
app.listen(8082,()=>{
console.log("服务器启动了")
})
定义全局中间件简化形式:
app.use((req,res,next)=>{
next();
})
可以使用app.use()连续定义多个中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序一次进行调用。
6.2.3 局部中间件
const express=require('express')
const app=express();
const mv=(req,res,next)=>{
console.log("我是一个局部中间件")
next()
}
app.get('/user',mv,(req,res)=>{
res.send("user")
})
app.get('/list',(req,res)=>{
res.send("list")
})
app.listen(8081,()=>{
console.log("服务器启动了")
})
定义多个局部中间件:
app.get('/user',mv,mv2,(req,res)=>{
res.send("user")
})
app.get('/user',[mv,mv2],(req,res)=>{
res.send("user")
})
6.2.4 中间件的作用
多个中间件之间,共享同一份req和res,基于这样的特性,可以在上游中间件中统一为req和res对象添加自定义的属性和方法,供下游的中间件或路由使用。
const express=require('express')
const app=express()
app.use((req,res,next)=>{
req.reqTime=Date.now()
console.log('我是一个中间件')
next()
})
app.get('/user',(req,res)=>{
res.send('user,请求时间:'+req.reqTime)
})
app.listen(8082,function(){
console.log('服务已经启动!')
})
6.2.5 使用中间件的注意事项
- 一定要在路由之前注册中间件
- 客户端发过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用next函数
- 为了防止代码逻辑混乱,调用next函数后不要再写额外的代码
- 连续调用多个中间件,多个中间件之间,共享req、res对象
6.3 中间件的分类
6.3.1 应用级别的中间件
通过app.use()或app.get()或app.post(),绑定到app实例上的中间件,叫做应用级别的中间件。
const express=require('express')
const app=express()
app.use((req,res,next)=>{
console.log('我是一个全局中间件')
next()
})
const mv=(req,res,next)=>{
console.log('我是一个局部中间件')
next()
}
app.get('/',mv,(req,res)=>{
res.send('Home page')
})
app.listen(8081,function(){
console.log('express server is running at http://127.0.0.1:8081')
})
6.3.2 路由级别的中间件
绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别,只不过,应用级别中间件是绑定到app实例上,路由级别中间件是绑定到router实例上。
const express=require('express')
const router=express.Rouer()
router.use((req,res,next)=>{
next()
})
module.exports=router
6.3.3 错误级别的中间件
错误级别中间件的作用:专门用来捕获整个项目中发送的异常错误,从而防止项目异常崩溃的问题。 格式:错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前往后,分别是(err,req,res,next) 注意: 错误级别的中间件必须注册到所有路由之后
const express=require('express')
const app=express()
app.get('/',(req,res)=>{
throw new Error('服务器内部发送错误')
res.send('Home page')
})
app.use((err,req,res,next)=>{
res.send('Error:'+err.message)
})
app.listen(8082,()=>{
console.log('express server is running at http://127.0.0.1:8082')
})
6.3.4 Express内置中间件
自Express4.16.0版本开始,Express内置了3个常用的中间件,极大的提高了Express项目的开发效率和体验。
- express.static快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)
- express.json解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
- express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
app.use(express.json())
app.post('/user',(req,res)=>{
res.send(req.body)
console.log(req.body)
})
app.use(express.urlencoded({extend:false}))
app.post('/add',(req,res)=>{
res.send(req.body)
console.log(req.body)
})
6.3.5 第三方中间件
非express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,可以按需下载并配置第三方中间件,从而提供项目的开发效率。 例如:在express@4.16.0之前的版本中,经常使用body-parser这个第三方中间件,来解析请求数据,使用步骤如下:
- 运行npm install body-parser安装中间件
- 使用require导入中间件
- 调用app.use(parser.urlencoded({extended:false}))注册并使用中间件
const express=require('express')
const parser=require('body-parser')
const app=express()
app.use(parser.urlencoded({extended:false}))
app.post('/user',(req,res)=>{
res.send(req.body)
console.log(req.body)
})
app.listen(8084,function(){
console.log('服务器已启动!')
})
7、接口跨域问题
正常通过express编写的接口由于访问协议的不同,不支持跨域请求。解决跨域请求的方案主要有两种:
- cors:主流方案,推荐使用
- jsonp:有缺陷的方案,只支持get请求
什么是cors? cors(Cross-Origin Resources Sharing,跨域资源共享)由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。 浏览器的同源安全策略默认会阻止网页跨域获取资源,但如果接口服务器配置了cors相关的HTTP响应头就可以解决浏览器的跨域访问限制。 cors是Express的一个第三方中间件,通过安装和配置cors中间件,可以很方便地解决跨域问题。
使用步骤如下:
- 运行npm i cors安装中间件
- 使用const cors=require(‘cors’)导入中间件
- 在路由之前调用app.use(cors())配置中间件
cors注意事项:
- cors主要在服务器端进行配置,客户端浏览器无须做任何额外的配置,即可请求开启了cors的接口
- cors在浏览器中有兼容性,只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了cors的服务接口(例如:IE10+,Chrome4+,FireFox3.5+)
8、nodemon
在编写测试node.js项目的时候,如果修改了项目的代码,则需要频繁的手动关闭再重新启动项目,非常繁琐,可以通过nodemon这个工具监听项目文件的变动,当代码被修改后,nodemon会自动重启项目,极大方便了开发和测试。 安装:
npm i nodemon -g
npm i nodemon -D
使用nodemon:
nodemon 要执行项目的路径
如果在终端执行nodemon命令时出现以下提示 在本机上搜索powerShell,再以管理员的方式打开,接着输入 set-ExecutionPolicy RemoteSigned 即可。
9、Node.js中操作mysql
9.1 安装mysql模块
mysql模块是托管与npm上的第三方模块,它提供了在Node.js项目中连接和操作MySQL数据库的能力。在项目中需要使用时,需要先将mysql安装为项目的依赖包。
npm install mysql
9.2 配置mysql模块
在使用mysql模块操作mysql数据库时,必须先对mysql模块进行必要的配置。
const mysql=require('mysql')
const db=mysql.createPool({
host:'127.0.0.1',
user:'root',
password:'123',
database:'test'
})
const sql="select * from user"
db.query(sql,function(err,res){
if(err) return console.log(err.message)
console.log(res)
})
9.3 mysql模块操作数据库
9.3.1 查询
const sql="select * from user"
db.query(sql,function(err,res){
if(err) return console.log(err.message)
console.log(res)
})
9.3.2 新增
const user={name:'小美',age:22,gender:1,phone:'186'}
const sql="insert into user(name,age,gender,phone) values(?,?,?,?)"
db.query(sql,[user.name,user.age,user.gender,user.phone],function(err,res){
if(err) return console.log(err.message)
if(res.affectedRows==1){
console.log('插入数据成功!')
}
})
插入数据的便捷方式: 如果插入数据时,数据对象的每个属性和数据表的字段一一对应,则可以通过如下方式快速插入数据:
const user={name:'小小',age:21,gender:2,phone:'186'}
const sql="insert into user set ?"
db.query(sql,user,function(err,res){
if(err) return console.log(err.message)
if(res.affectedRows==1){
console.log('插入数据成功!')
}
})
9.3.3 更新
const user={id:5,name:'小小2',age:21,gender:2,phone:'186150'}
const sql="update user set name=?,age=?,gender=?,phone=? where id=?"
db.query(sql,[user.name,user.age,user.gender,user.phone,user.id],function(err,res){
if(err) return console.log(err.message)
if(res.affectedRows==1){
console.log('修改数据成功!')
}
})
修改数据的便捷方式: 更新数据时,如果数据对象的每个属性与数据表的字段一一对应,则可以通过如下方式快速更新数据:
const user={id:5,name:'小小3',age:21,gender:2,phone:'150'}
const sql="update user set ? where id=?"
db.query(sql,[user,user.id],function(err,res){
if(err) return console.log(err.message)
if(res.affectedRows==1){
console.log('修改数据成功!')
}
})
9.3.4 删除
const sql="delete from user where id=5"
db.query(sql,5,function(err,res){
if(err) return console.log(err.message)
if(res.affectedRows==1){
console.log('删除数据成功!')
}
})
|