在 PHP 面试中,Session 与 Cookie 几乎是必考知识点。很多候选人能说出“Session 存在服务器,Cookie 存在浏览器”,但一旦追问“Session ID 是怎么传递的”“分布式环境下 Session 如何共享”,回答就开始模糊。本文从面试角度出发,系统梳理 Session 与 Cookie 的关系,并给出分布式 Session 的常见解决方案。
一、Session 与 Cookie 的本质区别
1. Cookie 是什么
Cookie 是服务器发送给浏览器并保存在客户端的一小段数据。浏览器后续请求同一域名时会自动携带它。Cookie 常见属性包括:
name=value:键值对Expires/Max-Age:过期时间Domain:生效域名Path:生效路径Secure:仅 HTTPS 传输HttpOnly:禁止 JavaScript 读取,降低 XSS 窃取风险SameSite:限制跨站请求携带,缓解 CSRF
PHP 中设置 Cookie:
setcookie('username', 'tom', time() + 3600, '/', '', false, true);
2. Session 是什么
Session 是服务器端保存用户状态的机制。PHP 默认通过 session_start() 开启会话,服务器生成一个唯一的 Session ID,并把用户数据保存在服务器端(默认文件存储)。Session ID 通常通过 Cookie 发给浏览器,浏览器下次请求时带回来,服务器据此找到对应会话数据。
session_start();
$_SESSION['user_id'] = 1001;
3. 两者的关系
一句话总结:Cookie 是 Session ID 的默认载体,Session 数据本身存在服务器。
- 服务器调用
session_start()时生成PHPSESSID - 该 ID 通过
Set-Cookie响应头写入浏览器 - 浏览器后续请求自动携带
Cookie: PHPSESSID=xxx - 服务器根据该 ID 读取对应的 Session 文件
如果浏览器禁用了 Cookie,PHP 也支持通过 URL 参数传递 Session ID(session.use_trans_sid),但这种方式安全性差,容易泄露,生产环境不推荐。
二、常见面试追问
1. Session 和 Cookie 哪个更安全?
不能简单说谁更安全。Session 数据在服务器端,客户端只持有 ID,相对不易被篡改;但 Session ID 若被窃取,攻击者同样可以冒充用户。Cookie 若存储敏感信息且未加密,风险更高。实际安全取决于传输是否 HTTPS、是否设置 HttpOnly、是否防 CSRF 等。
2. 关闭浏览器后 Session 一定失效吗?
不一定。Session 的过期由服务器端 session.gc_maxlifetime 控制,而浏览器关闭后 Cookie 是否消失取决于 Cookie 是否设置了过期时间。默认 PHPSESSID 是会话 Cookie,关闭浏览器后消失,但服务器端 Session 文件可能仍然存在,直到被垃圾回收。
3. Session 和 Cookie 的容量限制
Cookie 一般单个域名下约 4KB,数量也有限制。Session 容量取决于服务器存储和配置,理论上可以更大,但也不建议存放大对象。
三、为什么需要分布式 Session
单机时代,Session 文件存在本机,问题不大。但在分布式架构中,用户请求可能被负载均衡转发到不同服务器:
- 第一次请求落到 A 服务器,Session 写入 A
- 第二次请求落到 B 服务器,B 找不到该 Session,用户被判定未登录
这就是典型的 Session 不一致问题。常见解决思路有以下几种。
四、分布式 Session 解决方案
1. Session 粘滞(Sticky Session)
通过负载均衡配置,让同一用户的请求始终落到同一台服务器。
- 优点:实现简单,无需改代码
- 缺点:服务器故障会丢失 Session;扩容缩容时重新分配麻烦;负载可能不均
适合小型系统或临时方案,不推荐作为长期架构。
2. Session 复制
多台服务器之间同步 Session 数据。
- 优点:某台宕机后其他服务器仍有数据
- 缺点:网络开销大,服务器越多同步成本越高,存在延迟
适合服务器数量很少的场景,规模一大就不现实。
3. 集中式存储(推荐)
把 Session 统一存到外部共享存储,所有应用服务器都访问同一份数据。常见选择:
- Redis:性能高、支持过期、数据结构丰富,最常用
- Memcached:简单高效,但数据易失
- 数据库:持久化好,但性能一般,适合低并发
PHP 中可通过修改配置或实现 SessionHandlerInterface 接入 Redis:
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379');
session_start();
也可以自定义处理器:
class RedisSessionHandler implements SessionHandlerInterface
{
private $redis;
public function __construct($redis)
{
$this->redis = $redis;
}
public function open($savePath, $sessionName): bool
{
return true;
}
public function close(): bool
{
return true;
}
public function read($id): string
{
return (string)$this->redis->get('session:' . $id);
}
public function write($id, $data): bool
{
return $this->redis->setex('session:' . $id, 1800, $data);
}
public function destroy($id): bool
{
return $this->redis->del('session:' . $id) > 0;
}
public function gc($maxLifetime): int
{
return 0;
}
}
- 优点:无状态化应用服务器,扩展性强,故障影响小
- 缺点:引入额外组件,需要保证 Redis 高可用
4. JWT / Token 方案
把用户状态编码到 Token 中,由客户端保存,服务端不存 Session。
- 优点:天然支持分布式,服务端无状态
- 缺点:Token 撤销困难;不适合存储大量数据;需要处理续期和注销
适合 API、前后端分离场景,但不能完全替代传统 Session。
五、面试答题思路总结
回答这类问题时,可以按以下结构组织:
- 先说明 Cookie 与 Session 的本质区别和联系
- 指出 Session ID 默认通过 Cookie 传递
- 引出分布式场景下的 Session 不一致问题
- 对比粘滞、复制、集中存储、JWT 四种方案
- 给出推荐方案:Redis 集中存储 + 合理过期 + HTTPS + HttpOnly
这样回答既有概念,又有架构,还有落地细节,通常能给面试官留下较好的印象。
结语
Session 与 Cookie 不是对立关系,而是配合关系:Cookie 负责在客户端携带身份标识,Session 负责在服务端保存状态。理解这一点,再去看分布式 Session 的各种方案,思路就会清晰很多。实际项目中,Redis 集中存储是目前最主流、最平衡的选择,而 JWT 更适合无状态 API 场景。掌握这些,基本可以应对大多数 PHP 面试中的相关提问。
未经允许不得转载:任鹏个人博客 » PHP 面试题:Session 与 Cookie 的关系及分布式 Session 解决方案

