状态管理:cookie和session

cookie

cookie的组成

cookie是浏览器中特有的一个概念,它就像浏览器的专属卡包,管理着各个网站的身份信息。

每个cookie就相当于是属于某个网站的一个卡片,它记录了下面的信息:

  • key:键,比如「身份编号」
  • value:值,比如袁小进的身份编号「14563D1550F2F76D69ECBF4DD54ABC95」,这有点像卡片的条形码,当然,它可以是任何信息
  • domain:域,表达这个cookie是属于哪个网站的,比如yuanjin.tech,表示这个cookie是属于yuanjin.tech这个网站的
  • path:路径,表达这个cookie是属于该网站的哪个基路径的,就好比是同一家公司不同部门会颁发不同的出入证。比如/news,表示这个cookie属于/news这个路径的。(后续详细解释)
  • secure:是否使用安全传输(后续详细解释)
  • expire:过期时间,表示该cookie在什么时候过期

当浏览器向服务器发送一个请求的时候,它会瞄一眼自己的卡包,看看哪些卡片适合附带捎给服务器

如果一个cookie同时满足以下条件,则这个cookie会被附带到请求中

  • cookie没有过期
  • cookie中的域和这次请求的域是匹配的
    • 比如cookie中的域是yuanjin.tech,则可以匹配的请求域是yuanjin.techwww.yuanjin.techblogs.yuanjin.tech等等
    • 比如cookie中的域是www.yuanjin.tech,则只能匹配www.yuanjin.tech这样的请求域
    • cookie是不在乎端口的,只要域匹配即可
  • cookie中的path和这次请求的path是匹配的
    • 比如cookie中的path是/news,则可以匹配的请求路径可以是/news/news/detail/news/a/b/c等等,但不能匹配/blogs
    • 如果cookie的path是/,可以想象,能够匹配所有的路径
  • 验证cookie的安全传输
    • 如果cookie的secure属性是true,则请求协议必须是https,否则不会发送该cookie
    • 如果cookie的secure属性是false,则请求协议可以是http,也可以是https

如果一个cookie满足了上述的所有条件,则浏览器会把它自动加入到这次请求中
在前端index.js写入,为的是判断用户名是否正确,以及是否登陆上,避免了没有登陆的情况下就可以操作系统。

cookie 中间件

可以直接使用cookie中间件来帮助我们简化工作
安装

  1. npm i cookie-parser

引入

  1. let token = "";
  2. let cookies = document.cookie;
  3. //获取的到的cookie可能不止一个
  4. //每一个cookie是用;进行分割的
  5. //token=xxx;user=xxxx;id=xxxx;
  6. let cookieArr = cookies.split(";");
  7. //判断是否有名字叫token
  8. for (let i = 0; i < cookieArr.length; i++) {
  9. let item = cookieArr[i];
  10. //每一个cookie都是一个键值对 xxx=xxxxx
  11. let arr = item.split("=");
  12. if (arr[0] === "token") {
  13. token = arr[1];
  14. break;
  15. }
  16. }
  17. if (!token) {
  18. location.hash = "#/";
  19. return;
  20. } else {
  21. $.ajax({
  22. url: "/api/user/verify/woami",
  23. type: "GET",
  24. success: function (res) {
  25. if (res.code === 0) {
  26. $("#username").text(res.data.name);
  27. }
  28. else {
  29. location.hash = "#/";
  30. }
  31. }
  32. });
  33. $("#logout").on("click", function () {
  34. alert("确定退出吗?");
  35. $.ajax({
  36. url: "/api/user/verify/loginOut",
  37. type: "GET",
  38. success: function (res) {
  39. if (res.code === 0) {
  40. location.hash = "#/";
  41. }
  42. }
  43. })
  44. });
  45. }

在user中写入接受前端传送过来的数据并进行匹配
image.png
需要插入中间件拦截,

  1. const {pathToRegexp} = require("path-to-regexp");
  2. let needToToken = [
  3. {method:"GET",path:"/user"},
  4. {method:"DELETE",path:"/user/:id"},
  5. {method:"PUT",path:"/user/:id"},
  6. ]
  7. //测试path-to-regexp
  8. // function test(){
  9. // let reg = pathToRegexp("/user/:id");
  10. // console.log(reg.test("/user/1"));
  11. // }
  12. // test();
  13. //由于/api/user/:id真正对应的是/api/user/123这样的URI路径
  14. //因此,为了匹配是否URI路径对应,使用path-to-regexp模块
  15. module.exports = function(req,res,next){
  16. console.log("------->tokenMiddleware----->" + req.path + "------>" + req.method);
  17. let apis = needToToken.filter(item => {
  18. let reg = pathToRegexp(item.path);
  19. let flag = reg.test(req.path);
  20. return item.method == req.method && flag
  21. });
  22. console.log(apis.length);
  23. //如果apis数组中没有数据,证明没有需要过滤的页面
  24. if(apis.length <= 0){
  25. next();
  26. return;
  27. }
  28. let token = req.cookies.token;
  29. //如果cookie中没有,从req.headers.authorization取出
  30. if(!token){
  31. token = req.headers.authorization;
  32. }
  33. if(!token){
  34. res.send(resultUtil(null, 100, "请先登录", 1))
  35. return;
  36. }
  37. next();
  38. }

在后端index.js中,image.png