# 从 Cookie 到 Session

# 为什么需要 session

  • 通过 cookie 进行登录时会暴露一些隐私信息,而且容易被篡改
  • cookie 的存储大小是一定的限制的,但是 session 在服务端没有大小限制
  • cookie 和 session 其实是一体的,只是在前端是 cookie,在服务端对应的就是 session 了。如果 cookie 有风险,就完全可以将其做成标识,在服务端通过这个标识去解析 session 中的存储的数据
  • cookie 发送到服务端被解析后,作为 Session 存储对象的 key 值使用,存储更多信息。此时的 cookie 是一个标识,具体存储信息是它所对应的 value
  • 下面代码的逻辑,仅在登录时设置一次 cookie,在正式的业务中也是如此。后续通过解析 cookie 来判断是否已登录或权限问题
const http = require("http");
const querystring = require("querystring");

// session 存储对象
const SessionData = {};

// 设置 cookie 过期时间
function setCookieExpires() {
  const d = new Date();
  // 在当前时间加上24小时
  d.setTime(d.getTime() + 24 * 60 * 60 * 1000);

  // toGMTString 的格式:Sat, 11 Dec 2021 04:51:51 GMT
  return d.toGMTString();
}

const server = http.createServer((req, res) => {
  res.setHeader("Content-type", "application/json; text/plain; charset=utf-8");

  // 将 cookie 存储在 req.cookie 中
  req.cookie = {};
  // cookie 默认存在 req.headers.cookie, 形式 k1=v1; k2=v2;
  const cookieStr = req.headers.cookie || "";
  cookieStr.split("; ").forEach((item) => {
    const [key, val] = item.split("=");
    req.cookie[key] = val;
  });

  // 假如session中通过 userid 对应
  const userId = req.cookie.userid || `${Date.now()}_${Math.random() * 100000}`;

  // query 参数
  const [path, query] = req.url.split("?");
  req.path = path;
  req.query = querystring.parse(query);

  // 登录
  if (path === "/login-in") {
    const { username, password } = req.query;

    // 登录时在服务端通过 Session 来存储登录状态
    SessionData[userId] = { username, password };

    // 设置 cookie 以 Session 的 key 值来设置
    res.setHeader(
      "Set-Cookie",
      `userid=${userId}; path=/; httpOnly; expires=${setCookieExpires()}`
    );

    res.end(
      JSON.stringify({
        session: SessionData[userId],
        msg: "欢迎登录, cookie设置成了userid,登录状态保存在 session 中",
      })
    );
    return;
  }

  if (path === "/login-test") {
    const state = SessionData[req.cookie.userid];
    if (state) {
      res.end(
        JSON.stringify({
          session: SessionData[req.cookie.userid],
          msg: "已登录,从 session 中返回当前用户信息",
        })
      );
    } else {
      res.end("你还没有登录哦~");
    }
  }
});

server.listen(7788, () => {
  console.log("server is running at port 7788");
});