Hello,大家好,今天跟大家聊一下客户端与服务器进行会话时,常用的技术cookie和session。
很多小伙伴,在面试的时候,都会背“cookie是保存在客户端的,session是保存在服务器端的……”
八股文谁都会背,但仅仅会背诵,却不理解,知识点很快就会忘记。今天,我们就结合代码来讨论一下这背后的原理到底是怎样的。
1、为什么要有cookie和session这些东西
Http,它是无状态协议,服务端无法感知到浏览器的登录状态。
所以,判断用户是否登录的任务就交给了服务器。
服务器则需要另外找寻字段来存放状态信息,然后根据这个字段,选择是否允许用户访问相应的内容。
因此,cookie诞生了。
2、Cookie
2.1 Cookie简介
cookie 中文叫作 “曲奇饼”,不太清楚为什么叫这个名字。
它在http的请求头和响应头中,都有对应的字段存储它。
- 在请求头中是cookie
- 在响应头中是set-cookie
如下图,是一个请求头,携带着的cookie字段。

2.2 Cookie是怎么用的
cookie可以理解为:保存在你电脑上的一段个人信息。
咱就以最简单的登录场景为例:
如果你第一次访问B站,那你肯定还没有进行过登录,因此,你访问的请求头里肯定也没有cookie字段。
当你登录成功之后,响应头会返回给你一个set-cookie字段,标识着服务器分配给你的cookie。(你可以开启无痕浏览模式,访问B站试一下)

在接收到这个请求之后,你的浏览器会将cookie保存下来。
然后,在下次浏览的时候。浏览器会在请求头中添加这个cookie,给到服务器。
接着,服务器会对你这个cookie,进行识别,来判断你的登录状态。
我这里用一段nodejs代码,演示一下:服务端处理的逻辑。
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
app.use(cookieParser());
// 模拟用户数据库
const users = [
{ username: 'user1', password: 'pass1' },
];
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
// 设置登录成功的 cookie
res.cookie('loggedIn', true, { maxAge: 900000, httpOnly: true });
res.send('Login successful');
} else {
res.send('Login failed');
}
});
app.get('/protected', (req, res) => {
// 检查登录 cookie
if (req.cookies.loggedIn) {
res.send('This is a protected resource.');
} else {
res.send('You need to log in to access this resource.');
}
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
2.3 cookie存在不安全的问题
http携带着cookie,进行数据传输的时候,伴随着一定的风险。
万一这个请求被人劫持了咋办?
别人把http报文解析之后,你的个人信息username = zhangsan,不就完完全全地暴露出来了吗?
为了解决这个问题,session应运而生。
3、 Session是什么,以及怎么用
Session这个玩意,在我们日常使用的时候,就是一段ID。
这段ID,既不会暴露信息,又没有什么规律。
所以,它即便被别人劫持了,也不会出现信息泄露的风险。
Session一般有两种用法:
一个是放在url中,例如:某个站点是http://example.com,那么session数据可以作为url中的查询参数,放在其中:http://example.com/somepage?sessionId=123456。
另外一个是放在请求头cookie中。没错,它需要放在http请求头,配合cookie字段一起使用。
针对第二种场景,用nodjs代码展示如下:
const express = require('express');
const session = require('express-session');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo');
const bcrypt = require('bcryptjs');
const app = express();
// 连接MongoDB
mongoose.connect('mongodb://localhost:27017/userAuth', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 用户模型
const UserSchema = new mongoose.Schema({
username: String,
password: String
});
const User = mongoose.model('User', UserSchema);
// 设置会话中间件
app.use(
session({
secret: 'your_secret_key',
resave: false,
saveUninitialized: true,
store: MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/mysession' }), // 使用MongoDB存储会话
cookie: { secure: false } // 在HTTPS下设置为true
})
);
// 注册新用户
app.post('/register', async (req, res) => {
try {
const hashedPassword = bcrypt.hashSync(req.body.password, 8);
const user = new User({ username: req.body.username, password: hashedPassword });
await user.save();
res.send('用户注册成功');
} catch (error) {
res.status(500).send('用户注册失败');
}
});
// 用户登录
app.post('/login', async (req, res) => {
try {
const user = await User.findOne({ username: req.body.username });
if (user && bcrypt.compareSync(req.body.password, user.password)) {
req.session.userId = user._id;
res.send('登录成功');
} else {
res.status(401).send('用户名或密码错误');
}
} catch (error) {
res.status(500).send('登录失败');
}
});
// 用户登出
app.get('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
return res.send('会话销毁失败');
}
res.send('你已退出登录');
});
});
// 受保护的路由
app.get('/protected', (req, res) => {
if (req.session.userId) {
// 验证用户ID是否存在于数据库中
User.findById(req.session.userId, (err, user) => {
if (err || !user) {
return res.status(401).send('用户验证失败');
}
res.send('欢迎回来,这是受保护的页面!');
});
} else {
res.status(401).send('请先登录');
}
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
在这里,我们使用mongodb来存储用户数据。
用户在登录成功之后,便把mongodb中存放的用户ID(_id)数据放入set-cookie字段中,返回给浏览器。

当浏览器再次访问时,它将在http请求头的cookie字段中,携带这个sessionid,进行会话。

4、最后总结
从上面的案例中可以看到,在使用session的时候,我们其实是在使用_id进行登录状态验证的。
当服务端拿到_id之后,会去检查_id,是否存在于mongodb数据库中。如果存在,则证明用户是正常登录的,可以展示给他对应的用户数据。
而cookie则是直接使用保存在浏览器中的用户名进行比较,相对来说,安全性会更差一些。
这就是为什么八股文里会讲:cookie保存在客户端,session保存在服务端的原因了。
1375

被折叠的 条评论
为什么被折叠?



