# 从 Cookie 到 Session
# 为什么需要 session
- 通过 cookie 进行登录时会暴露一些隐私信息,而且容易被篡改
- cookie 的存储大小是一定的限制的,但是 session 在服务端没有大小限制
- cookie 和 session 其实是一体的,只是在前端是 cookie,在服务端对应的就是 session 了。如果 cookie 有风险,就完全可以将其做成标识,在服务端通过这个标识去解析 session 中的存储的数据
# session 配合 cookie 实现登录
- 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");
});