
在 symfony 或 sulu 项目中,若通过数据库插入访问日志却始终无法生成新记录、仅返回已有 id,很可能是 http 请求被全站缓存(如 sulu 的 http 缓存或 symfony 的反向代理缓存)拦截,导致控制器逻辑根本未执行。本文提供两种可靠解决方案。
在 symfony 或 sulu 项目中,若通过数据库插入访问日志却始终无法生成新记录、仅返回已有 id,很可能是 http 请求被全站缓存(如 sulu 的 http 缓存或 symfony 的反向代理缓存)拦截,导致控制器逻辑根本未执行。本文提供两种可靠解决方案。
在基于 Sulu(构建于 Symfony 之上)的项目中,你可能会遇到这样一种典型问题:明明执行了 INSERT INTO custom_tracking ... 并调用 $conn->lastInsertId(),但返回的 ID 总是上一条记录的 ID,且数据库中并未新增任何行。这并非 SQL 语法错误或主键配置问题,而极大概率源于 HTTP 层缓存机制绕过了 PHP 控制器执行。
Sulu 默认启用 aggressive HTTP 缓存策略——对已发布页面,会直接由 Web 服务器(如 Nginx)或 Symfony 的 HttpCache 返回静态响应,完全跳过控制器逻辑。因此,你写的插入语句根本不会被执行,lastInsertId() 实际返回的是此前某次 真实执行 时的旧 ID(例如浏览器刷新触发了缓存穿透后的上一次成功插入),造成“数据未新增但 ID 在变”的错觉。
✅ 正确解决路径如下:
方案一:禁用特定路由的 HTTP 缓存(推荐用于管理后台或非公开接口)
在控制器方法上添加 @NoCache 注解(Sulu)或显式设置响应头(Symfony 原生):
// 使用 Sulu 的注解(需启用 SuluHttpCacheBundle)
use Sulu\Component\HttpCache\Annotation\NoCache;
/**
* @NoCache
*/
public function trackAction(Request $request): Response
{
$conn = $this->entityManager->getConnection();
$stmt = $conn->prepare(self::INSERT_TRACKING_SQL);
$stmt->bindValue(':utidId', $utid_db_id, \PDO::PARAM_INT);
$stmt->bindValue(':url', $url, \PDO::PARAM_STR);
$stmt->bindValue(':urlParams', $urlParams, \PDO::PARAM_STR);
$stmt->execute();
$trackingId = $conn->lastInsertId();
return new JsonResponse(['id' => (int) $trackingId]);
}同时确保该路由未被全局缓存规则匹配(检查 sulu_http_cache.yaml 或 framework.cache 配置)。
方案二:前端异步上报(推荐用于用户侧页面埋点)
完全规避服务端缓存影响,改由 JavaScript 在页面加载完成后发起独立 AJAX 请求:
// 页面底部或 DOMContentLoaded 后执行
fetch('/api/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
utidId: {{ utid_db_id|json_encode }},
url: window.location.href,
urlParams: new URLSearchParams(window.location.search).toString()
})
}).catch(console.error);后端对应轻量接口(同样建议加 @NoCache):
#[Route('/api/track', name: 'api_track', methods: ['POST'])]
#[NoCache]
public function apiTrackAction(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true);
// 执行同上的 INSERT 逻辑...
return $this->json(['success' => true]);
}⚠️ 注意事项:
- 不要依赖
lastInsertId()在高并发场景下返回绝对唯一 ID;如需强一致性,请改用RETURNING id(PostgreSQL)或事务内SELECT LAST_INSERT_ID()(MySQL)并加锁; - 确保
custom_tracking表主键为AUTO_INCREMENT(MySQL)或SERIAL(PostgreSQL),且无INSERT ... ON DUPLICATE KEY UPDATE类逻辑干扰; - 开发阶段务必禁用生产级缓存(如设置
APP_ENV=dev或关闭SULU_HTTP_CACHE_ENABLED),避免调试失真。
通过以上任一方案,即可确保每次用户访问都真实触发日志写入,彻底解决“ID 复用、数据不新增”的缓存陷阱。


















