前言
本文讲解一下Cookie的一些基础知识,以及简单应用,最后会通过一个简单的登录的例子来讲解,会使用node作为后端,大家可以进行参考!
什么是Cookie?
Cookie是网站在用户浏览器上存储的小型文本数据,由网站在用户访问时创建并发送到浏览器,浏览器会保存这些数据并在后续请求中将其发送回服务器。Cookie的主要目的是实现状态管理,让无状态的HTTP协议能够"记住"用户和会话信息。
Cookie的工作原理
- 服务器创建:当用户首次访问网站时,服务器通过HTTP响应头
Set-Cookie
发送Cookie到浏览器 - 浏览器存储:浏览器接收到Cookie后会将其存储在本地
- 自动发送:之后对该网站的所有请求,浏览器都会自动通过HTTP请求头
Cookie
将存储的Cookie发送回服务器 - 服务器读取:服务器接收到请求后,可以读取Cookie中的信息来识别用户或会话
如何使用Cookie
接下来,作者将通过一个用户登录的简单案例,来讲解Cookie的常见用法--作为登录凭证
(先展示代码,下面会详细讲解)
项目结构:
后端 server.js
我们先用node.js创建创建服务器写一个简单的后端登录程序:
(由于这里没有连接数据库,就不进行登录逻辑的验证了,直接登录成功,返回Cookie)
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
//首页接口
if (req.method == 'GET' &&
(req.url == '/' || req.url == '/index.html')) {
fs.readFile(//传递两个参数 路径,和回调函数
path.join(__dirname,'public', 'index.html'),
(err, content) => {
if (err) {
res.writeHead(500); // 5XX 服务器错误
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(content);
})
}
if (req.method == 'GET' && req.url == '/style.css') {
fs.readFile(
path.join(__dirname, 'public', 'style.css'),
(err, content) => {
if (err) {
res.writeHead(500);
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/css' })
res.end(content);
}
);
return;
}
if (req.method == 'GET' && req.url == '/script.js') {
fs.readFile(
path.join(__dirname, 'public', 'script.js'),
(err, content) => {
if (err) {
res.writeHead(500);
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/javascript' })
res.end(content);
}
);
return;
}
//上述都是基本的获取资源的接口,下面才是业务逻辑的接口,请着重看下面的代码
//登录接口
if (req.method == 'POST' && req.url == '/login'){
//这里按理来讲要对请求中的账号密码进行验证 由于着重讲解Cookie的使用 就不验证了
res.writeHead(200,{
'Set-Cookie': "user=admin",
'Content-Type': 'application/json'
})
res.end(
JSON.stringify({
success:true,
msg:'登录成功'
})
)
}
//验证登录接口
if (req.method == "GET" && req.url == "/check-login"){
const cookies = Object.fromEntries(req.headers.cookie?.split(';').map(c => c.trim().split('=')) || []);
if(cookies.user === 'admin'){
res.writeHead(200,{
'Content-Type': 'application/json'
})
res.end(JSON.stringify({
isLogin:'ok'
}))
}
else {
res.writeHead(200,{
'Content-Type': 'application/json'
})
res.end(JSON.stringify({
isLogin:'fail'
}))
}
}
})
server.listen(8080);
前端 index.html + style.css + script.js
展示script.js
const loginForm = document.getElementById('loginForm');
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value.trim();
try{
const response = await fetch('/login',{
method:'POST',
headers: {
'Content-Type':'application/json'
},
body: JSON.stringify({
username,
password
})
})
const data = await response.json();
}
catch{
console.log('登录出错了')
}
})
document.addEventListener('DOMContentLoaded',async ()=>{
try {
const response = await fetch('/check-login')
const data =await response.json();
console.log(data);
if(data.isLogin == "ok"){
document.getElementById('loginSection').style.display = 'none';
document.getElementById('welcomeSection').style.display = 'block';
document.getElementById('userDisplay').textContent = data.username;
}
else if(data.isLogin == "fail"){
document.getElementById('loginSection').style.display = 'block';
document.getElementById('welcomeSection').style.display = 'none';
}
}catch{
}
})
分析代码流程
让我们来分析代码流程,分析Cookie在这个登录程序中的作用吧
首页展示
首先当我们输入localhost:8080时,会得到以下的页面,
这是我们项目结构中的html和css部分,实际上,还是通过server.js后端服务拿到页面资源,它识别到http://localhost:8080/
返回首页资源;它识别到http://localhost:8080/style.css
返回css资源;它识别到http://localhost:8080/script.js
,返回js资源,然后浏览器就可以拿到这些,通过渲染构建出我们想看的画面,html和css部分加上script.js我们就称为前端代码了,用于渲染页面(html+css)以及给后端发送请求(script.js)。
相关代码:
//首页接口
if (req.method == 'GET' &&
(req.url == '/' || req.url == '/index.html')) {
fs.readFile(//传递两个参数 路径,和回调函数
path.join(__dirname,'public', 'index.html'),
(err, content) => {
if (err) {
res.writeHead(500); // 5XX 服务器错误
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(content);
})
}
if (req.method == 'GET' && req.url == '/style.css') {
fs.readFile(
path.join(__dirname, 'public', 'style.css'),
(err, content) => {
if (err) {
res.writeHead(500);
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/css' })
res.end(content);
}
);
return;
}
if (req.method == 'GET' && req.url == '/script.js') {
fs.readFile(
path.join(__dirname, 'public', 'script.js'),
(err, content) => {
if (err) {
res.writeHead(500);
res.end('Server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/javascript' })
res.end(content);
}
);
return;
}
登录请求
当我们在表单中输入账号密码,点击Login时
此刻会发送POST请求login给后端服务器server.js
服务器会返回请求体为JSON的response给前端
并且注意哦,这个时候服务器返回的response也会携带Cookie哦!我们现在可以在浏览器中看到服务器返回的Cookie呢
相关代码:
if (req.method == 'POST' && req.url == '/login'){
//这里按理来讲要对请求中的账号密码进行验证 由于着重讲解Cookie的使用 就不验证了
res.writeHead(200,{
'Set-Cookie': "user=admin", //response中携带Cookie
'Content-Type': 'application/json'
})
res.end(
JSON.stringify({
success:true,
msg:'登录成功'
})
)
}
登录验证
此时我们再刷新页面,可以看到下面的效果:
这是因为刷新页面时,给后端服务发送了check-login的请求
并且能够看到,此时前端发送的请求中携带了Cookie,后端的check-login的接口验证发现有这个Cookie,于是就返回一个成功的response,于是客户端就可以更改页面结构了!
相关代码:
if (req.method == "GET" && req.url == "/check-login"){
const cookies = Object.fromEntries(req.headers.cookie?.split(';').map(c => c.trim().split('=')) || []);
if(cookies.user === 'admin'){
res.writeHead(200,{
'Content-Type': 'application/json'
})
res.end(JSON.stringify({
isLogin:'ok'
}))
}
else {
res.writeHead(200,{
'Content-Type': 'application/json'
})
res.end(JSON.stringify({
isLogin:'fail'
}))
}
}
这里的代码略微有点复杂,我们需要分析一下: 首先识别到前端发送了check-login请求,于是进入请求处理:
将前端发送的Cookie分析一下:
Pycharm-843fbaf3=1bf2ebc3-3548-4f69-9583-e1cdac448210; Webstorm-e54c2519=9edffdde-495d-4c06-8b16-9f2d01a20e72; user=admin
- 按
;
分割:将整个 Cookie 字符串拆分成多个键值对 - 去除空格并拆分键值:对每个键值对进行
trim()
和split('=')
- 转换为对象:使用
Object.fromEntries()
将数组转为对象
输出结果:
{
"Pycharm-843fbaf3": "1bf2ebc3-3548-4f69-9583-e1cdac448210",
"Webstorm-e54c2519": "9edffdde-495d-4c06-8b16-9f2d01a20e72",
"user": "admin"
}
通过解析Cookie并验证,发现前端存在刚刚后端服务给出的Cookie,所以返回isLogin:'ok'
,
前端接收到后端返回的isLogin:'ok'
之后,进行页面的处理:
if(data.isLogin == "ok"){
document.getElementById('loginSection').style.display = 'none';
document.getElementById('welcomeSection').style.display = 'block';
document.getElementById('userDisplay').textContent = data.username;
}
else if(data.isLogin == "fail"){
document.getElementById('loginSection').style.display = 'block';
document.getElementById('welcomeSection').style.display = 'none';
}
所以就达到了我们想要的效果!
总结这个案例中Cookie的作用
在这个登录功能的案例中,Cookie 扮演了以下几个关键角色:
1. 身份认证的凭证
- 当用户首次登录成功时,服务器通过
Set-Cookie
响应头返回一个Cookie(user=admin
) - 这个Cookie就相当于服务器颁发的"身份证明",后续请求中浏览器会自动携带这个Cookie
2. 会话状态的维持
- 浏览器会存储这个Cookie(默认在关闭浏览器前都有效)
- 每次刷新页面时,浏览器会自动在请求头中带上这个Cookie(
Cookie: user=admin
) - 这样服务器就能识别出这是已经登录过的用户
3. 权限验证的依据
-
在访问
/check-login
接口时:- 服务器解析请求中的Cookie
- 验证是否存在
user=admin
这个键值对 - 根据验证结果返回不同的登录状态
4. 实现"免登录"效果
-
因为Cookie会被浏览器持久化存储:
- 即使用户关闭页面再打开,只要Cookie未过期
- 系统仍然能识别出已登录状态
- 不需要用户重复输入账号密码
关键流程总结
- 首次登录 → 服务器下发Cookie
- 后续请求 → 浏览器自动携带Cookie
- 状态检查 → 服务器验证Cookie有效性
- 界面展示 → 根据Cookie验证结果动态显示内容
Cookie的替代方案
虽然Cookie非常有用,但在某些场景下可能需要考虑替代方案:
-
Web Storage API(localStorage/sessionStorage):
- 更大的存储空间(通常5MB)
- 数据不会自动发送到服务器
- 更适合纯客户端存储
-
IndexedDB:
- 客户端数据库,适合存储大量结构化数据
-
JWT(JSON Web Token) :
- 无状态认证方案
- 可以存储在Cookie、localStorage或内存中
实际应用场景
- 用户认证:存储Session ID或Token
- 个性化设置:存储用户的语言、主题偏好等
- 购物车功能:临时存储用户选择的商品
- 跟踪和分析:用户行为分析(需注意隐私合规)
- 跨页面状态保持:在多页面应用中保持状态
总结
Cookie是Web开发中不可或缺的技术,它解决了HTTP无状态的问题,使得网站能够"记住"用户和会话信息。正确使用Cookie需要理解其工作原理、安全属性和最佳实践。随着Web技术的发展,虽然出现了Web Storage等替代方案,但Cookie在特定场景下仍然是不可替代的解决方案。
在实际开发中,应根据具体需求合理选择存储方案,并始终将安全性放在首位,遵循最小权限原则,保护用户数据和隐私。