node --- > [express] cookie/session 机制与 中间件的使用(路由守卫)

53 篇文章 0 订阅
49 篇文章 0 订阅

说明

  • 源代码
  • 记忆、遗忘回顾
  • 使用 cookie/session 机制,让 客户端/服务器 的访问变得有状态

cookie 与 session

  • 由于 HTTP 协议的无状态性,当一次连接断开后. 服务器并不会记录用户是否登录. 因此需要引入 cookie/session 机制

cookie

cookie: 浏览器在电脑硬盘中开辟的一块空间,主要供服务器端存储数据

  • cookie 中的数据是以域名的形式进行区分的.

  • cookie 中的数据是有过期时间的,超过时间数据会被浏览器自动删除.

  • cookie 中的数据会随着请求被自动发送到服务器

    1.客户端第一次向服务器端发送请求的时候,是不存在 cookie 的.
    2.服务端验证客户端,会响应一个 cookie 给客户端.
    3.客户端验证通过后,在发送请求会自动带上 cookie


session

session:实际上就是一个对象,存储在服务器端的内存中,在 session 对象中也可以存储多条数据,每一条数据都有一个 sessionid 做为唯一标识.

注意:cookie 在客户端的磁盘中,session 在服务端的内存中


cookie 和 session 的使用(理论)

  1. [client] --> 邮件地址、密码 --> [server]
  2. server 端,对邮箱地址、密码进行验证,若通过则生成 sessionid
  3. [client] <-- sessionid(存储在客户端的 cookie 中) <-- [server]
  4. 客户端再次登录
  5. [client] --> cookie [server]
  6. 服务端,获取 cookie 中的 sessionid,验明身份后,响应数据

实战: cookie 与 session

  • 配置获取POST请求参数
// 配置获取post参数
const bodyParser = require('body-parser')
// extended: false 方法内部使用querystring模块处理请求参数的格式
// extended: true  方法内部使用第三方模块qs处理请求参数的格式
// 拦截所有请求
app.use(bodyParser.urlencoded({ extended: false }))
  • 验证成功后,生产session信息
const User = require('../../model/user')
const session = requier('express-session')
app.use(session({ secret: 'secret key' }))
admin.post('/login', async (req, res) => {
  const { email, password } = req.body
  const user = await User.findOne({ email })
  // 假设登录成功
  req.session.username = user.username // 此处能用req.session是在app.js中使用app.use方法进行了拦截
})
  • User是使用mongoose的接口创建的集合规则
  • User.findOne(): 通过邮箱再数据库中查找数据
  • req.session.username: 执行后,会在内存中创建
    在这里插入图片描述

中间件的使用

什么是中间件

  • 中间件就是一堆方法
  • 可以接收客户端发来的请求、可以对请求做出响应,也可以将请求继续交给下一个中间件继续处理.
  • 将一个复杂的请求处理逻辑分开处理
  • 也可以将请求到达指定路由前,先进行验证处理: 如用户是否登录

中间件的构成

  • 中间件方法以及请求处理函数
  • 中间件方法: 由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求.
app.get('请求路径', '处理函数');   // 接收并处理get请求
app.post('请求路径', '处理函数');   // 接收并处理post请求
  • 可以对同一请求设置多个中间件,对同一请求进行多次处理
  • 默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配
  • 可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件.
app.get('/request', (req, res, next) =>{
  req.name = "张三";
  next();
})
app.get('/request', (req,res) =>{
  res.send(req.name);
});

app.use的使用

  • 它有2个参数, 第一个参数不写对所有路径的请求进行拦截
  • 若填写了第一个参数,则对该路径下的路由进行拦截
  • 第二个参数是路由处理函数
// 拦截所有路由
app.use((req,res,next)=>{
  console.log(req.url);
  next();
})

// 拦截 /admin 下的所有路由
app.use('/admin', (req, res, next)=>{
  console.log(req.url);
  next()
})

路由守卫

  • 简单的说就是在所有路由前面或者后面,针对特定路径或所有路径的一个特殊的app.use方法.

登录守卫

  • 放在所有的路由前面,即客户端访问第一个经过的函数
// 拦截 -> 路由守卫
app.use('/admin', require('./middleware/loginGuard'))

// 其他路由中间件
app.get(...);
app.post(...);
  • loginGuard
module.exports = (req, res, next) => {
  if (req.url !== '/login') {
    // 访问的不是登录页面
    // 判断用户是否登录
    if (req.session.username) {
      next()
    } else {
      res.redirect('/admin/login')
    }
  } else {
    // 访问的是登录页面
    next()
  }
}
  • next: 将执行权,传递给下一个中间件
  • res.redirect: 重定向到路由 /admin/login

错误守卫

  • 放在比较靠后的中间件. 用来收集错误信息
// 其他路由中间件
app.get(...);
app.post(...);

// 错误 -> 路由守卫
app.use(require('./middleware/errorGuard.js'))
  • 当其他路由发现错误时(如验证不通过),使用next将执行权往后传递.
  • 传递到最后,有错误守卫对错误信息进行收集.
  • 发现错误并传递错误的代码(部分)如下:
// 比如在更新用户信息的时候,新传递的数据和数据库里面的格式不符合
try {
  await validateUser(req.body)
} catch (ex) {
  return next(JSON.stringify({ path: '/admin/user-edit', msg: ex.message }))
}

validateUser: 是验证用户信息的一个函数,验证通过返回true,否则会抛出异常.
catch: 用于捕获异常.
return: 是阻止程序向下执行.
JSON.stringfify: 是因为app.use(param1,param2)中的param2的第一个参数err只接收一个字符串类型.因此需要使用该方法将对象转换成字符串

  • 此时函数的执行权,交给了下一个中间件errorGuard.js
module.exports = (err, req, res, next) => {
  const result = JSON.parse(err)
  let params = []
  for (let attr in result) {
    if (attr != 'path') {
      params.push(attr + '=' + result[attr])
    }
  }
  res.redirect(`${result.path}?${params.join('&')}`)
}
  • 它将收集到的参数拼接成get请求的参数部分. 然后重定向
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值