NodeJS SessionToken验证⑧

news2024/11/24 4:34:14

文章目录

  • ✨文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持😘
  • 前言
  • 登录鉴权Cookie&Session
  •    ExpressSession中间件
  •    MVC演示
  • 登录鉴权JSON Web Token (JWT)
  •    Jsonwebtoken参数
    • sign 方法
    • verify 方法
  •    封装JsonWebToken
  •    校验异常情况Verify
  •    阿贾克斯Interceptors
  •    代码实现步骤 演示
    • 1、访问Login 获取打开登录页面
    • 2、输入登录密码完成登录(登录成功设置token)
    • 3、登录成功后端设置(请求拦截器成功前 设置localStorage token) 并且返回响应头(header)
    • 4、首页发送数据接口请求...
    • 5、App 入口
  • 总结


✨文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持😘

                    ⡖⠒⠒⠒⠤⢄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸   ⠀⠀⠀⡼⠀⠀⠀⠀ ⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢶⣲⡴⣗⣲⡦⢤⡏⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠋⠉⠉⠓⠛⠿⢷⣶⣦⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⠀⠀⠘⡇⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⠀⠀⠀⠀⠀⠀⠀⢰⠇⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⡴⠊⠉⠳⡄⠀⢀⣀⣀⡀⠀⣸⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢸⠃⠀⠰⠆⣿⡞⠉⠀⠀⠉⠲⡏⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⢧⡀⣀⡴⠛⡇⠀⠈⠃⠀⠀⡗⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣱⠃⡴⠙⠢⠤⣀⠤⡾⠁⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⡇⣇⡼⠁⠀⠀⠀⠀⢰⠃⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣸⢠⣉⣀⡴⠙⠀⠀⠀⣼⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⡏⠀⠈⠁⠀⠀⠀⠀⢀⡇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢸⠃⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⣰⠃⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣀⠤⠚⣶⡀⢠⠄⡰⠃⣠⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⢀⣠⠔⣋⣷⣠⡞⠀⠉⠙⠛⠋⢩⡀⠈⠳⣄⠀⠀⠀⠀⠀⠀⠀
⠀⡏⢴⠋⠁⠀⣸⠁⠀⠀⠀⠀⠀ ⠀⣹⢦⣶⡛⠳⣄⠀⠀⠀⠀⠀
⠀⠙⣌⠳⣄⠀⡇   不能   ⡏⠀⠀  ⠈⠳⡌⣦⠀⠀⠀⠀
⠀⠀⠈⢳⣈⣻⡇   白嫖 ⢰⣇⣀⡠⠴⢊⡡⠋⠀⠀⠀⠀
⠀⠀⠀⠀⠳⢿⡇⠀⠀⠀⠀⠀⠀⢸⣻⣶⡶⠊⠁⠀⠀
⠀⠀⠀⠀⠀⢠⠟⠙⠓⠒⠒⠒⠒⢾⡛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣠⠏⠀⣸⠏⠉⠉⠳⣄⠀⠙⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⡰⠃⠀⡴⠃⠀⠀⠀⠀⠈⢦⡀⠈⠳⡄⠀⠀⠀⠀⠀⠀⠀
⠀⠀⣸⠳⣤⠎⠀⠀⠀⠀⠀⠀⠀⠀⠙⢄⡤⢯⡀⠀⠀⠀⠀⠀⠀
⠀⠐⡇⠸⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡆⢳⠀⠀⠀⠀⠀⠀
⠀⠀⠹⡄⠹⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠸⡆⠀⠀⠀⠀⠀
⠀⠀⠀⠹⡄⢳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡀⣧⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢹⡤⠳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣷⠚⣆⠀⠀⠀⠀
⠀⠀⠀⡠⠊⠉⠉⢹⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡎⠉⠀⠙⢦⡀⠀
⠀⠀⠾⠤⠤⠶⠒⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠒⠲⠤⠽   

前言

  1. Node.js是一个javascript运行环境。它让javascript可以开发后端程序,实现几乎其他后端语言实现的所有功能,可以与```PHP、Java、Python、.NET、Ruby等后端语言平起平坐。
  2. Nodejs是基于V8引擎,V8是Google发布的开源JavaScript引擎,本身就是用于Chrome浏览器的JS解释,但是Node之父 Ryan Dahl在这里插入图片描述把这V8搬到了服务器上,用于做服务器的软件。

登录鉴权Cookie&Session

鉴权说明 :「HTTP 无状态」我们知道,HTTP 是无状态的。也就是说,HTTP 请求方和响应方间无法维护状态,都是一次性的,它不知道前后的请求都发生了什么。但有的场景下,我们需要维护状态。最典型的,一个用户登陆微博,发布、关注、评论,都应是在登录后的用户状态下的 「标记」 ,那解决办法是什么呢?

Cookie&Session 图示 ↓

在这里插入图片描述

  • 使用库 : npm install express-session 、 npm install connect-mongo
  • expressSession NPM :https://www.npmjs.com/package/express-session
  • connectmongo NPM :https://www.npmjs.com/package/connect-mongo

   ExpressSession中间件

//注册session中间件
app.use(session({
  name: "先生", //session名字
  secret: "serverz~qwer", //服务器生成 session 的签名
  cookie: {
    maxAge: 1000 * 60 * 60, //过期时间
    secure: false // 为 true 时候表示只有 https 协议才能访问cookie
  },
  rolling: true, 为 true 表示 超时前刷新,cookie 会重新计时; 为 false 表示在超时前刷新多少次,都是按照第一次刷新开始计时。
  resave: true, //重新设置session后, 会自动重新计算过期时间
  saveUninitialized: true, 强制将为初始化的 session 存储
  
  //通过connect-mongo 存储数据库、过期自动销毁、创建新的sesstion储存数据库
  store: MongoStore.create({ 
    mongoUrl: 'mongodb://127.0.0.1:27017/Oyande', //新创建了一个数据库
    ttl: 1000 * 60 * 60 // 过期时间
  })
}))

   MVC演示

– 登录校验接口

//登录校验接口
router.post("/login", UserController.login)
router.get("/logout", UserController.logout)

APP.js管理
//设置中间件,sesssion过期校验
app.use((req, res, next) => {
  //排除login相关的路由和接口
  if (req.url.includes("login")) {
    next()
    return
  }

  if (req.session.user) {
    //重新设置以下sesssion
    req.session.mydate = Date.now()
    next()
  } else {
    //是接口, 返回错误码
    //不是接口,就重定向
    req.url.includes("api")
      ? res.status(401).json({ ok: 0 }) : res.redirect("/login")
  }
})

– M

    login: (username, password) => {
        return UserModel.find({ username, password })
    }

– V

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>登录页面</h1>

    <div>
        <div>用户名:<input id="username" /></div>
        <div>密码:<input type="password" id="password" /></div>
        <div><button id="login">登录</button></div>
    </div>

    <script>
        var username = document.querySelector("#username")
        var password = document.querySelector("#password")
        var login = document.querySelector("#login")

        login.onclick = () => {
            console.log(username.value, password.value)
            fetch("/api/login", {
                method: "POST",
                body: JSON.stringify({
                    username: username.value,
                    password: password.value,
                }),
                headers: {
                    "Content-Type": "application/json"
                }
            }).then(res => res.json()).then(res => {
                console.log(res)
                if (res.ok === 1) {
                    location.href = "/"
                } else {
                    alert("用户名密码不匹配")
                }
            })
        }
    </script>
</body>

</html>

– C

  login: async (req, res) => {
    const { username, password } = req.body
    const data = await UserService.login(username, password)
    if (data.length === 0) {
      res.send({
        ok: 0
      })
    } else {
      //设置session {}  
      req.session.user = data[0] //设置session对象, 
      //默认存在内存中。
      res.send({
        ok: 1
      })
    }
  },

  logout: (req, res) => {
    req.session.destroy(() => {
      res.send({ ok: 1 })
    })
  }

演示

在这里插入图片描述

  • 缺点

    1. 内容过大时会裂开
    2. CSRF伪造

登录鉴权JSON Web Token (JWT)

  • session 缺点 :占内存,占空间,容易跨平台伪造 ,CSRF伪造攻击

  • JSON Web Token (JWT) 使用步骤说明 :session 换成 localstorage ,数据储存在localstorage,防止加密的数据(签名)被反推出来 需要 添加 密钥。

使用Session 图示

在这里插入图片描述

使用JSON Web Token (JWT) 图示

在这里插入图片描述

  • 总结
  1. 当然, 如果一个人的token 被别人偷走了, 那也没办法,会认为小偷就是合法用户, 这其实和一个人的session id 被别人偷走是一样的。

  2. 这样一来, 就不保存session id , 只是生成token , 然后验证token , 用CPU计算时间获取session 存储空间 !

  3. 解除了session id这个负担, 可以说是无事一身轻, 机器集群现在可以轻松地做水平扩展, 用户访问量增大, 直接加机器就行。 这种无状态的感觉实在是太好了!

缺点

  1. 占带宽,正常情况下要比 session_id 更大,需要消耗更多流量,挤占更多带宽,假如你的网站每月有 10 万次的浏览器,就意味着要多开销几十兆的流量。听起来并不多,但日积月累也是不小一笔开销。实际上,许多人会在 JWT 中存储的信息会更多;

  2. 无法在服务端注销,那么久很难解决劫持问题;

  3. 性能问题,JWT 的卖点之一就是加密签名,由于这个特性,接收方得以验证 JWT 是否有效且被信任。对于有着严格性能要求的 Web 应用,这并不理想,尤其对于单线程环境。

注意

  • CSRF攻击的原因是浏览器会自动带上cookie,而不会带上token;

  • 以CSRF攻击为例 ↓

    cookie:用户点击了链接,cookie未失效,导致发起请求后后端以为是用户正常操作,于是进行扣款操作;token:用户点击链接,由于浏览器不会自动带上token,所以即使发了请求,后端的token验证不会通过,所以不会进行扣款操作;

  • 使用库 Jsonwentoken : https://www.npmjs.com/package/jsonwebtoken

  • 使用库 axios : https://www.npmjs.com/package/axios

   Jsonwebtoken参数

sign 方法

说明:sign方法用于生成一个jwt字符串,该方法接收四个参数,依次如 👇

0、jsonwebtoken.sign(payload, secretOrPrivateKey, [options, callback]);

参数

1、接收一个对象,用于传入用户身份信息

2、接收一个字符串,作为jwt.signature的加密密钥

3、options包括以下选项

  1. algorithm:加密算法(默认值:HS256)
  2. expiresIn:支持秒表示或描述时间跨度zeit / ms的字符串。如60,“2 days”,“10h”,“7d“ 过期时间
  3. notBefore:定义在什么时间之前,该jwt都是不可用的。支持秒表示或描述时间跨度zeit / ms的字符串。如:60,“2days”,“10h”,“7d”
  4. issuer:jwt签发者
  5. jwtid: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
  6. subject:jwt所面向的用户
  7. noTimestamp
  8. header
  9. keyid
  10. mutatePayload

4、callback(err,token):生成jwt结束时执行的回调函数,遵循nodejs的错误优先原则,第一个参数是生成jwt过程抛出的异常信息,第二个参数是成功生成的jwt字符串值

❗注意 : 需要注意的是,一旦指定了sign方法的第四个参数回调函数,则sign方法变为异步方法,jwt字符串只能通过回调函数获取。

verify 方法

说明:verify方法用于校验和解析jwt字符串,该方法入参四个参数,如👇

1、token:jwt字符串

2、secret:加密密钥

3、options:配置对象 配置如下

  1. algorithms 签名加密算法,默认为HS256
  2. audience 受众
  3. complete 默认为false,表示只返回payload解密数据,若为true表示返回{ payload, 1. header, signature }解密数据
  4. issuer 签发人
  5. ignoreExpiration if true do not validate the expiration of the token.
  6. ignoreNotBefore if true do not validate the not before of the token.
  7. subject 主题
  8. clockTolerance number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers
  9. maxAge the maximum allowed age for tokens to still be valid.
  10. clockTimestamp the time in seconds that should be used as the current time for all necessary comparisons.
  11. nonce if you want to check nonce claim, provide a string value here. It is used on Open ID for the ID Tokens.

4、callback(err,decode):回调函数,遵循nodejs错误优先原则,第一个参数是异常信息,第二个参数是根据jwt解码出来的数据

❗注意1 : 需要注意其中complete属性,该属性为true,则根据jwt字符串解码出来完整数据,即包含header,payload,signature,否则只包含payload

❗注意2 : 一旦verify传入callback,verify方法不再同步返回解码数据,但是verify入参callback并不是异步执行的,而是同步执行的。

   封装JsonWebToken

规范文件路径 util/JWT.js

const jwt = require("jsonwebtoken")
const secret = "guoxiansheng"
const JWT = {
	//获取的token 格式 XXX.XXX.XXX
    generate(value, expires) {
        return jwt.sign(value, secret, { expiresIn: expires }) //内容数据、密钥、token的时长
        //第四个回调函数(err,token)=>{} 
    },
    verify(token) {
        try {
            return jwt.verify(token, secret,{complete:false}) //加密的token 、 密钥
			//第四个回调函数(err,token)=>{} 
        } catch (error) {
            return false
        }
    }
}
module.exports = JWT

   校验异常情况Verify

  1. NotBeforeError 该异常发生在jwt尚未生效时使用
  1. TokenExpiredError 该异常发生在jwt字符串校验成功,但是已失效
  1. JsonWebTokenError 该异常发生在
规范文件路径 util/JWT.js

const jwt = require("jsonwebtoken")
const secret = "guoxiansheng"
const JWT = {
	//获取的token 格式 XXX.XXX.XXX
    generate(value, expires) {
        return jwt.sign(value, secret, { expiresIn: expires,notBefore:'0.2h' }) //内容数据、密钥、token的时长
        //第四个回调函数(err,token)=>{} 
    },
    verify(token) {
        try {
            return jwt.verify(token, secret,{complete:false}) //加密的token 、 密钥
			//第四个回调函数(err,token)=>{} 
        } catch (error) {
            return false
        }
    }
}
module.exports = JWT

   阿贾克斯Interceptors

   <script>
        //拦截器,
        //请求发出前,执行的方法
        axios.interceptors.request.use(function (config) {
            return config;
        }, function (error) {
            return Promise.reject(error);
        });

		//请求成功后 ,第一个调用的方法
        axios.interceptors.response.use(function (response) {
            return response;
        }, function (error) {
            return Promise.reject(error);
        });
    </script>

   代码实现步骤 演示

1、访问Login 获取打开登录页面

html

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
   <script>
       //拦截器,
       axios.interceptors.request.use(function (config) {
           return config;
       }, function (error) {
           return Promise.reject(error);
       });

       axios.interceptors.response.use(function (response) {
           const { authorization } = response.headers
           authorization && localStorage.setItem("token", authorization)
           return response;
       }, function (error) {
           return Promise.reject(error);
       });
   </script>
</head>

<body>
   <h1>登录页面</h1>

   <div>
       <div>用户名:<input id="username" /></div>
       <div>密码:<input type="password" id="password" /></div>
       <div><button id="login">登录</button></div>
   </div>

   <script>
       var username = document.querySelector("#username")
       var password = document.querySelector("#password")
       var login = document.querySelector("#login")

       login.onclick = () => {
           axios.post("/api/login", {
               username: username.value,
               password: password.value,
           }).then(res => {
               console.log(res.data)
               if (res.data.ok === 1) {
                   location.href = "/"
               } else {
                   alert("用户名密码不匹配")
               }
           })
       }
   </script>
</body>

</html>

接口

//使用到ejs
var express = require('express');
var router = express.Router();

router.get('/', function (req, res, next) {
  res.render('login', { title: 'Express' });
});

module.exports = router;

2、输入登录密码完成登录(登录成功设置token)

登录判断

 login: async (req, res) => {
   const { username, password } = req.body
   const data = await UserService.login(username, password)
   if (data.length === 0) {
     res.send({
       ok: 0
     })
   } else {
     //设置token 
     const token = JWT.generate({
       _id: data[0]._id,
       username: data[0].username
     }, "1d")
     //token返回在header
     res.header("Authorization", token)
     //默认存在内存中。
     res.send({
       ok: 1
     })
   }
 },

3、登录成功后端设置(请求拦截器成功前 设置localStorage token) 并且返回响应头(header)

   <script>
       //拦截器,
       axios.interceptors.request.use(function (config) {
           return config;
       }, function (error) {
           return Promise.reject(error);
       });

       axios.interceptors.response.use(function (response) {
           const { authorization } = response.headers
           authorization ?.localStorage.setItem("token", authorization)
           return response;
       }, function (error) {
           return Promise.reject(error);
       });
   </script>

4、首页发送数据接口请求…

说明:首页发送数据接口请求,且 首页设置 “阿贾克斯” 请求拦截器,请求前(获取localStorage token) 且 设置请求头(headers),app.js(设置中间件判断token,通过后返回响应头) , 请求成功前(重新设置localStorage token),出错(移除token,重定向到 /login)

前端代码

<!DOCTYPE html>
<html>

<head>
 <title>
   首页
 </title>
 <link rel='stylesheet' href='/stylesheets/style.css' />
 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
 <script>
   //请求发出前,执行的方法
   axios.interceptors.request.use(function (config) {
     const token = localStorage.getItem("token")
     config.headers.Authorization = `Bearer ${token}`
     return config;
   }, function (error) {
     return Promise.reject(error);
   });

   // 请求成功后 ,第一个调用的方法
   axios.interceptors.response.use(function (response) {
     const {
       authorization
     } = response.headers
     authorization && localStorage.setItem("token", authorization)
     return response;
   }, function (error) {
     if (error.response.status === 401) {
       localStorage.removeItem("token")
       location.href = "/login"
     }
     return Promise.reject(error);
   });
 </script>
</head>
<body>
 <script>
   //获取列表
   axios.get("/api/user?page=1&limit=10").then(res => {
     res = res.data
     var tbody = document.querySelector("tbody")
     tbody.innerHTML = res.map(item => `
         <tr>
           <td>${item._id}</td>  
           <td>${item.username}</td>  
           <td>${item.age}</td>  
         </tr>
       `).join("")
   })
 </script>
</body>

</html>

5、App 入口

//设置中间件,token过期校验
app.use((req, res, next) => {
  //排除login相关的路由和接口
  if (req.url.includes("login")) {
    next()
    return
  }

  const token = req.headers["authorization"]?.split(" ")[1]
  if (token) {
    const payload = JWT.verify(token)
    if (payload) {
      //重新计算token过期时间
      const newToken = JWT.generate({
        _id: payload._id,
        username: payload.username
      }, "1d")
      res.header("Authorization", newToken)
      next()
    } else {
      res.status(401).send({ errCode: -1, errInfo: "token过期" })
    }
  } else {
    next()
  }
})

总结

以上是个人学习Node的相关知识点,一点一滴的记录了下来,有问题请评论区指正,共同进步,这才是我写文章的原因之,如果这篇文章对您有帮助请三连支持一波

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/630743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

北邮22信通:第六章查找:BST树表(代码超详细逐步图解)

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 获取更多文章 请访问专栏&#xff1a; 北邮22信通_青山如墨雨如画的博客-CSDN博客 目录 讲解 1.构造函数 2.析构函数 3.查询函数 4.删除操作 &#xf…

全新出品!阿里 P5 工程师~P8 架构师晋升路线揭秘

阿里巴巴终于公开了从初级程序员到架构师的学习路线图&#xff0c;这里相对应的基本上就是从P5到P8的晋升体系&#xff01;今天老师将会带着大家从初级程序员开始一点点分享整个晋升体系&#xff01; 职级&#xff1a;初级程序员 薪资&#xff1a;6-12K 开发年限&#xff1a;0-…

PureComponent和Component的区别和底层处理机制

PureComponent和Component都是React中的组件类&#xff0c;但它们在实现细节和使用上有些差别。 Component是React中定义组件的基类&#xff0c;它的shouldComponentUpdate方法默认返回true&#xff0c;也就是说&#xff0c;每次调用setState或forceUpdate方法都会引发组件重新…

代码随想录第55天

1.判断子序列&#xff1a; 动态规划五部曲分析如下&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]。 注意这里是判断s是否…

百度新闻源调整:自媒体权重降低,官方媒体优势突显

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 根据黑猫发稿的消息&#xff0c;自6月1日起&#xff0c;百度新闻源取消了大部分自媒体新闻源的收录&#xff0c;包括搜狐自媒体、企鹅号、网易号&#xff0c;甚至百度自己的百家号也受到了影响。 …

X2000 Linux 低功耗

一、进入休眠 当系统启动后&#xff0c;在命令终端输入&#xff1a; echo mem> /sys/power/state 即可立即进入休眠&#xff0c;功耗也随之降低。 二、配置中断唤醒GPIO 1、确认kernel默认配置文件 进入到/tools/iconfigtool/IConfigToolApp/路径下&#xff0c;执行./…

【Pm4py第四讲】关于Conversion

本节用于介绍pm4py中的转换函数&#xff0c;包括日志、事件流、数据块的转换、Petei网、流程树、BPMN的转换、可达图、面向对象日志等。 1.函数概述 本次主要介绍Pm4py中一些常见的转换函数&#xff0c;总览如下表&#xff1a; 函数名说明convert_log_to_networkx&#xff08;…

Java(30天拿下---第一天)

Java开发&#xff08;30天拿下---第一天&#xff09; 一 hello world以及JDK,JRE,JVM二 转义字符三 注释四 代码规范五 DOS命令&#xff08;了解&#xff09;六 变量1.加号的使用2.数据类型整型浮点型字符类型布尔类型自动类型转换强制类型转换String类型 七 API文档 一 hello …

React | Redux的使用详解

✨ 个人主页&#xff1a;CoderHing &#x1f5a5;️ React.js专栏&#xff1a;React.js Redux的使用详解 &#x1f64b;‍♂️ 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f4ab; 系列专栏&#xff1a;吊打面试官系列 16天学会Vue 7天学会微信小程序 N…

亚马逊云科技Serverless数据分析,助力猎豹移动构建更高性价比数据仓库

也许你也听过这样一句话&#xff1a;“21世纪什么最贵&#xff1f;人才&#xff01;”当数字经济全面席卷而来&#xff0c;这个问题的答案不可置否地变为了“数据”。通过数据分析获取近乎实时的洞察&#xff0c;以驱动业务的全流程&#xff0c;是企业数字化转型的必经之路。借…

【文末送书】微服务拆分规范

目录 一. &#x1f981; 什么是微服务&#xff1f;二. &#x1f981; 拆分模型Ⅰ. 压力模型拆分1. 垂直拆分&#xff08;Vertical Decomposition&#xff09;2. 水平拆分&#xff08;Horizontal Decomposition&#xff09;3. 动态拆分&#xff08;Dynamic Decomposition&#x…

初识网络之http协议

目录 一、http协议含义 二、 认识URL 三、urlencode与urldecode 1. urlencode 2. urldecode 四、http协议响应与请求格式 1. http协议请求格式 2.http协议响应格式 3. http请求实际形式 3.1 程序准备 3.2 浏览器发起请求 3.3 请求行内容 3.4 请求报头内容 4. htt…

2022年国赛高教杯数学建模E题小批量物料的生产安排解题全过程文档及程序

2022年国赛高教杯数学建模 E题 小批量物料的生产安排 原题再现 某电子产品制造企业面临以下问题&#xff1a;在多品种小批量的物料生产中&#xff0c;事先无法知道物料的实际需求量。企业希望运用数学方法&#xff0c;分析已有的历史数据&#xff0c;建立数学模型&#xff0c…

mysql联合索引详解

比较简单的是单列索引&#xff08;btree&#xff09;。遇到多条件查询时&#xff0c;不可避免会使用到多列索引。联合索引又叫复合索引。 btree结构如下&#xff1a; 每一个磁盘块在mysql中是一个页&#xff0c;页大小是固定的&#xff0c;mysql innodb的默认的页大小是16k&a…

【工作中遇到的性能优化问题】

项目场景&#xff1a; 页面左侧有一列表数据&#xff0c;点击列表项会查对应的表格数据和表单信息&#xff08;表单是根据数据配置生成的&#xff09;&#xff0c;并在右侧展示。如果数据量大&#xff0c;则非常卡。 需要对此页面进行优化。 问题描述 问题一、加载左侧数据时…

systemV的工作原理+原理代码

概念 我们知道进程间的通信有管道的方式进程通信管道制作_云的小站的博客-CSDN博客 但是我们的管道通信其实属于一种取巧的方式&#xff0c;利用了打开的文件可读写的特性上&#xff0c;两个进程对此分别进行读写操作就会产生所谓的通信现象&#xff0c;但是外面的管道依旧得…

【社区图书】快速入门go程序开发——《Go程序开发实战宝典》书评

《Go程序开发实战宝典》书评 一、介绍二、简要概述三、内容分析3.1、第一部分&#xff1a;Go语言基础知识3.2、第二部分&#xff1a;介绍服务端开发经常需要处理的问题3.3、第三部分&#xff1a;Go语言开发实践实战案例 四、我的看法和评价4.1、对本书整体评价4.2、我对这本书的…

Office Visio 2021安装

哈喽&#xff0c;大家好。今天一起学习的是Visio 2021的安装&#xff0c;这是一个绘制流程图的软件&#xff0c;用有效的绘图表达信息&#xff0c;比任何文字都更加形象和直观。Office Visio 是office软件系列中负责绘制流程图和示意图的软件&#xff0c;便于IT和商务人员就复杂…

Vue.js 中的插槽和动态组件

Vue.js 中的插槽和动态组件 Vue.js 是一款流行的 JavaScript 框架&#xff0c;它提供了一种简单而灵活的方式来构建交互式 Web 应用程序。在 Vue.js 中&#xff0c;插槽和动态组件是两个常用的概念。它们可以帮助开发者更方便地组织和管理组件的结构和行为。但是这两个概念有什…

(opencv)图像几何变换——平移

图像的平移操作是将图像的所有像素坐标进行水平或垂直方向移动&#xff0c;也就是将所有像素点按照给定的偏移量在水平方向沿x轴、垂直方向上沿y轴移动。平移变换分为两种类型&#xff1a;图像大小变化与图像大小不变。第一种类型保证图像平移的完整信息&#xff0c;第二种图像…