
浏览器对 302 重定向存在强缓存行为,导致短时间内重复请求被直接复用缓存响应(跳过 php 执行),造成点击未写入数据库;通过强制使用 307 临时重定向并禁用所有客户端缓存可彻底解决。
该问题并非源于 PHP 或 MySQL 逻辑错误,而是典型的HTTP 缓存陷阱:现代浏览器(Chrome、Edge 等)在收到 302 Found 重定向响应时,会自动对相同 URL(如 thisphpfile.php?link=1)的后续请求进行缓存优化——即使服务端 PHP 脚本尚未执行,浏览器也可能直接复用上一次重定向的 Location 响应头,跳过服务器端处理,从而导致 INSERT 语句完全未被执行。
默认 header("Location: ...") 发送的是 302 Found 状态码,而浏览器对 302 的缓存策略较为宽松(尤其在短时间、相同参数下),这正是你观察到“1 分钟内多次点击只入库一次”“普通窗口无效但无痕窗口有效”的根本原因:无痕模式禁用了历史缓存,因此每次请求都真实到达服务器。
✅ 正确解法是显式声明 307 Temporary Redirect 状态码,并配合严格的缓存控制头,确保每次请求都强制交由 PHP 处理:
// ✅ 替换原有的 header("Location: ...") 为以下四行:
header('HTTP/1.1 307 Temporary Redirect');
header('Cache-Control: no-cache, no-store, must-revalidate'); // 禁止任何缓存
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); // 过期时间设为过去
header('Pragma: no-cache'); // 兼容 HTTP/1.0
header('Location: ' . $link_sql, true, 307); // 第三参数显式指定状态码
exit(); // 强烈建议添加,防止后续代码意外执行⚠️ 注意事项:
立即学习“PHP免费学习笔记(深入)”;
- 307 语义明确:要求客户端保持原始请求方法(GET)和参数重发请求到新地址,完全符合跳转场景,且不被浏览器缓存重定向结果;
- 必须在 header() 前确保无任何输出(包括空格、BOM、echo),否则会触发 headers already sent 错误;
- exit() 或 die() 应紧随重定向之后,避免重定向后继续执行后续逻辑;
- SQL 注入风险仍存在:当前 $link 校验为白名单方式(== '1'),虽安全但建议升级为预处理语句或更健壮的整型校验(如 (int)$link === 1);
- 数据库字段名 DATE 是 MySQL 保留字,建议改用 created_at 并用反引号包裹或重命名,避免潜在语法冲突。
综上,这不是数据库或脚本逻辑缺陷,而是 HTTP 协议层与浏览器实现的协同效应。通过精准控制状态码与缓存策略,即可在不改动业务逻辑的前提下,实现每一次点击的精确追踪。










