Express

express

安装:npm install express
启动:node ./app.js

注:npm init -y 在所在目录安装包管理配置文件

创建express

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

监听get请求

// 4.监听客户端的get post请求,并相应具体内容
// res.send()
app.get('/user',(req,res)=>{
  // 向客户端响应JSON对象
  res.send({
    name:'张三',
    age:20,
    gender:'男'
  })
})

监听post请求

// res.send()
app.post('/user',(req,res)=>{
  // 向客户端响应文本字符串
  res.send('请求成功')
})

获取url中携带的查询参数

// req.query
app.get('/',(req,res)=>{
  // req.query可获取客户端的url查询参数 默认是空对象
  console.log(req.query)
  res.send(req.query)
})

获取url中的动态参数

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

托管静态资源

// 调用express.static()
// ./js为静态资源目录,调取资源是目录本身不在url中
app.use(express.static('./js'))

托管多个静态资源

多次调用express.static(),依次查找,找到停止

挂载路径前缀

// 调用express.static()
app.use('/js',express.static('./js'))

nodemon

自动重启
安装:npm install -g nodemon
启动:nodemon ./app.js

路由

映射关系 比如10086一个按键对应一个服务
Express中的路由
请求类型,URL,处理函数

// 请求类型,URL,处理函数
app.post('/user',(req,res)=>{
  // 向客户端响应文本字符串
  res.send('请求成功')
})

模块化路由

  1. 创建路由对应js文件
  2. 调用express.Router()函数创建路由对象
  3. 向路由对象上挂载具体路由
  4. 使用module.exports向外共享路由对象
  5. 使用app.use()函数注册路由模块

注册路由模块

// router.js
const express=require('express')
const router=express.Router()

router.get('/user/list',(req,res)=>{
  res.send('Get userList')
})
router.post('/user/add',(req,res)=>{
  res.send('add new user')
})

module.exports=router
// express.js
const express=require('express')
const app=express()

const router=require('./router')
// app.use()注册全局中间件
app.use(router)

app.listen(8081,()=>{
  console.log('express server running at http://127.0.0.1:8081');
})

为路由模块添加统一前缀

// express.js
app.use('/api',router)

Express中间件

中间处理的环节,拥有输入输出,类似于多级处理排污水

调用流程

客户端对服务器的请求,连续调用多个中间件对请求进行预处理,处理完毕后服务器再响应回客户端。

中间件的格式

app.post('/user',(req,res,next)=>{
 // 包含next的为中间件函数
  next()
})

next()函数的作用

next()交给下一个函数处理,实现多个中间件函数调用,路由为最终处理环节

定义中间件函数

// 定义中间件
const mw=(req,res,next)=>{
  console.log('最简单的中间件')
  next()
}

注册全局中间件

app.use(mw)

中间件化简

app.use((req,res,next)=>{
  console.log('中间件化简')
  next()
})

中间件的作用

多个中间件可以共享同一份res和req,因此可以再上游中间件中统一为他们添加自定义方法属性,供下游使用。

app.use((req,res,next)=>{
  // 到达服务器事件
  const time=Date.now()
  // 赋值给req传递给下游函数
  req.startTime=time
  next()
})

app.get('/',(req,res)=>{
  res.send('home page'+req.startTime)
})

定义多个全局中间件

app.use()并行,从上到下运行中间件

局部生效的中间件

不使用app.use()

// 局部中间件
const mw=(req,res,next)=>{
  console.log('最简单的中间件')
  next()
}

// 中间件只在该路由生效
app.get('/',mw,(req,res)=>{
  res.send('home page')
})

app.get('/user',(req,res)=>{
  res.send('home page')
})

定义多个局部中间件

// 中间件只在该路由生效
app.get('/',mw1,mw2,(req,res)=>{res.send('home page')})
app.get('/u',[mw1,mw2],(req,res)=>{res.send('home page')})

注意事项

  • 中间件放在路由之前
  • 可连续调用多个中间件
  • 中间件一定要调用next()
  • next()要放在最后
  • 多个中间件共享req和res

中间件分类

分类函数
应用级别use(),get(),post(),绑定在app上的中间件
路由级别express.Router()
错误级别防止出错(err,req,res,next)
内置级别express.static(),express.json(),express.urlencoded()
第三方中间件body-parser

错误级别中间件

// 错误级别中间件
app.get('/u2',(req,res)=>{
  // 人为的制造错误
  throw new Error('服务器内部发生错误')
  res.send('home page')
})
// 防止项目崩溃
// 必须注册在所有路由之后(例外)
app.use((err,req,res,next)=>{
  console.log('发生了错误'+err.message);
  res.send('Error'+err.message)
})

内置中间件

express.json()

//app.use(express.json())
app.use(express.json())
app.post('/user',(req,res)=>{
  // 服务器可以使用req.body接受客户端发送过来的请求体数据
  console.log(req.body);
  // 不配置中间件,则为undefine
  res.send('home page')
})

服务器可以使用req.body接受客户端发送过来的请求体数据
如果不配置任何解析的中间件,则req.body默认为undefine
在这里插入图片描述
express.urlencoded()

// app.use(express.urlencoded({extended:false}))
app.use(express.urlencoded({extended:false}))
app.post('/user',(req,res)=>{
  // 服务器可以使用req.body接受客户端发送过来的请求体数据
  console.log(req.body);
  // 不配置中间件,则为undefine
  res.send('home page')
})

在这里插入图片描述

第三方中间件

body-parser
安装:npm i body-parser

const parser=require('body-parser')
app.use(parser.urlencoded({extended:false}))

app.post('/user',(req,res)=>{
  console.log(req.body);
  res.send('home page')
})

自定义中间件

解析表单数据

  1. 定义中间件
  2. 监听req的data事件
  3. 监听req的end事件
  4. 使用querystring来解析请求数据
  5. 数据挂载在req.body
  6. 封装

自己写解析表单数据中间件

// 导入内置的querystring模块
const qs=require('querystring')
// 解析表单数据的中间件
app.use((req,res,next)=>{
  // 保存客户端请求体
  let str=''
  // 监听req.data
  req.on('data',(chunk)=>{
    str+=chunk
  })
  req.on('end',()=>{
    // 把字符串解析成对象
    const body=qs.parse(str)
    // console.log(body);
    req.body=body
    next()
  })
})

app.post('/user',(req,res)=>{
  res.send(req.body)
})

封装

// express
const customBodyParser=require('./fengzhuang')
app.use(customBodyParser)

app.post('/user',(req,res)=>{
  res.send(req.body)
})
// 封装页面
const qs=require('querystring')
const bodyParser=(req,res,next)=>{
  // 保存客户端请求体
  let str=''
  // 监听req.data
  req.on('data',(chunk)=>{
    str+=chunk
  })
  req.on('end',()=>{
    // 把字符串解析成对象
    const body=qs.parse(str)
    // console.log(body);
    req.body=body
    next()
  })
}
module.exports=bodyParser

Express写接口

创建服务器

// 导入express
const express=require('express')
// 创建服务器实例
const app=express()

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

创建api路由模块

// express.js
// 导入express
const express=require('express')
// 创建服务器实例
const app=express()
const router=require('./apiRouter.js')
app.use('/api',router)
// 启动服务器
app.listen(8080,()=>{
  console.log('http://127.0.0.1:8080')
})
// router.js
const express=require('express')
const router=express.Router()
// 挂载对应路由

module.exports=router

编写get接口

// 挂载对应路由
router.get('/get',(req,res)=>{
  // 通过req.query获取客户端查询字符串的树
  const query=req.query
  res.send({
    status:0,
    msg:'get 请求成功',
    data:query
  })
})

编写post接口

// express.js
// 一定要配置中间件来解析body
app.use(express.urlencoded({extended:false}))
// router.js
router.post('/post',(req,res)=>{
  // 一定要配置中间件来解析body
  const body=req.body
  res.send({
    status:0,
    msg:'post 请求成功',
    data:body
  })
})

跨域问题

CORS中间件

安装:npm install cors

// 在路由之前配置cors中间件
const cors=require('cors')
app.use(cors())

CORS响应头

  • res.setHeader(‘Access-Contorl-Allow-Origin’,‘指定url’)
  • res.setHeader(‘Access-Contorl-Allow-Headers’,‘额外(9个)请求头’)
  • res.setHeader(‘Access-Contorl-Allow-Methods’,‘POST’,‘DELETE’)

简单请求和预检请求区别
简单请求:与服务器之间只会发生一次请求
预检请求:发生两次,option预检成功后发送真正的请求

JSONP

// 在配置cors之前配置jsonP
app.get('/api/jsonp',(req,res)=>{
  const funname=req.query.callback
  const data={name:'zs',age:30}
  const scriptStr=`${funname}(${JSON.stringify(data)})`
  res.send(scriptStr)
})

前后端身份认证

cookie

在这里插入图片描述

session的认证机制

在这里插入图片描述

配置express-session中间件

安装:npm install express-session
注册:

const session=require('express-session')
app.use(session({
	secret:'zifuchuan',
	resave:false,
	saveUninitialized:true
}))

使用session存储登录信息

app.post('/api/login',(req,res)=>{
  if(req.body.username!=='admin'||req.body.password!='000000'){
    return res.send({status:1,msg:'登陆失败'})
  }

  req.session.user=req.body
  req.session.isLogin=true

  res.send({
    status:0,
    msg:"登录成功"
  })
})

使用session取数据

app.get('/api/username',(req,res)=>{
  if(!req.session.isLogin){
    return res.send({status:1,msg:'没有登录'})
  }
  res.send({
    status:0,
    msg:'success',
    username:req.session.user.username
  })
})

清空session

app.post('/api/logout',(req,res)=>{
  req.session.destroy()
  res.send({
    status:0,
    msg:'退出成功'
  })
})

JWT(JSON Web Token)认证机制

session身份认证需要结合cookie,因为cookie不支持跨域,如果前后端跨域,则使用jwt进行前后端身份认证。
在这里插入图片描述
组成部分:Header.Payload.Signature
Header Signature:确保Token的安全性
Payload:加密信息

在服务器生成并返回Token之后,通常会存储在客户端的localStorage或者sessionStorage中
每次请求都要将该字符串放在http请求头的Authorization字段中
Authorization:Bearer <token>

安装jwt相关

安装
npm i jsonwebtoken express-jwt
jsonwebtoken:将json数据生成为jwt字符串
express-jwt:将jwt字符串解析还原成json数据

导入

const jwt=require('jsonwebtoken')
const expressJWT=require('express-jwt')

定义secret加密解密密钥

  • 加密
const secretKey='12as4d56a4d'
 // 在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
 // 用户信息 加密密钥 配置token的有效期
 const tokenStr=jwt.sign({username:userinfo.username},secretKey,{expiresIn:'30s'})
 res.send({
   status: 200,
   message: '登录成功!',
   token: tokenStr // 要发送给客户端的 token 字符串
 })
  • 解密
// 注册将 JWT 字符串解析还原成 JSON 对象的中间件
// 通过加密密钥去解密json
// unless配置不需要访问权限接口
// app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]}))
app.use(expressJWT({secret:secretKey,algorithms:['HS256']}).unless({path:[/^\/api\//]}))

使用 req.user 获取用户信息

只要配置了express-jwt,那么用户信息就在req.user中获取,user是自己在解密的时候设置的。

// 这是一个有权限的 API 接口
app.get('/admin/getinfo', function (req, res) {
  // 使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
  console.log(req.user);
  res.send({
    status: 200,
    message: '获取用户信息成功!',
    data: req.user // 要发送给客户端的用户信息
  })
})

捕获解析jwt失败后产生的错误

// 使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
app.use((err,req,res,next)=>{
  if(err.name==='UnauthorizedError'){
    //token解析失败所致
    return res.send({
      status:401,
      message:'无效的token'
    })
  }
  res.send({
    status:500,
    message:'未知错误'
  })
})

mysql

安装
npm install mysql

  1. npm init -y
  2. npm install mysql

导入模块

//导入mysql模块
const mysql=require('mysql')
//建立数据库连接
const db=mysql.createPool({
  host:'127.0.0.1',
  user:'root',
  password:'123456',
  database:'databasename'
})

测试数据库是否连接

db.query('select 1',(err,results)=>{
  if(err) return console.log(err);
  console.log(results);
})

查询数据

const sqlStr='select * from manage_log'
// 如果是select,那么查询的结果是数组
db.query(sqlStr,(err,result)=>{
  if(err) return console.log('查询数据失败');
  console.log(result);
})

新增数据

const worker={
  work_pwd:'000000',
  work_name:'express',
  work_tech:'',
  Authority:1
}
// 如果是insert,那么results是一个对象 通过affectedRows判断是否插入成功
const sqlStr2='insert into work_info(work_id,work_pwd,work_name,work_tech,Authority) values (?,?,?,?,?)'
db.query(sqlStr2,[null,worker.work_pwd,worker.work_name,worker.work_tech,worker.Authority],
(err,results)=>{
  if(err) return console.log(err.message);
  if(results.affectedRows===1){
    console.log('插入数据成功')
  }
})

新增数据(便捷)

如果数据和字段一一对应,那么

const sqlStr2='insert into work_info set ?'
db.query(sqlStr2,worker,(err,results)=>{
  if(err) return console.log(err.message);
  if(results.affectedRows===1){
    console.log('插入数据成功')
  }
})

更新数据

// 更新数据
const worker1={
  work_pwd:'111111',
  work_name:'ex',
  work_tech:'',
  Authority:1,
  work_id:3
}
const sqlStr3='update work_info set work_pwd=?,work_name=? where work_id=?'
// 如果是update,那么results是一个对象 通过affectedRows判断是否插入成功
db.query(sqlStr3,[worker1.work_pwd,worker1.work_name,worker1.work_id],(err,results)=>{
  if(err) return console.log(err.message);
  if(results.affectedRows===1){
    console.log('更新成功');
  }
})

更新数据(便捷)

如果数据和字段一一对应,那么

const sqlStr3='update work_info set ? where work_id=?'
db.query(sqlStr3,[worker1,worker1.work_id],(err,results)=>{
  if(err) return console.log(err.message);
  if(results.affectedRows===1){
    console.log('更新成功');
  }
})

删除数据

const sqlStr4='delete from work_info where work_id=?'
// 如果是delete,那么results是一个对象 通过affectedRows判断是否插入成功
db.query(sqlStr4,3,(err,results)=>{
  if(err) return console.log(err)
  if(results.affectedRows===1){
    console.log('删除数据成功')
  }
})

标记删除
模拟删除,设置status字段,来标记是否被删除,调用update来更改status状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值