问题背景
本地开发中,直接访问 /api/chatsessions 能实时获取 PostgreSQL 的最新数据。但部署至服务器跑 PM2、Nginx 反代后,却始终返回旧内容,数据库更新后网页依旧不刷新。
排查步骤
1. 确认 Route Handler 类型
/api/chatsessions 是 App Router 的 Route Handler(route.ts),默认是动态的,但仍可能使用 数据缓存(Data Cache) ,导致返回旧数据 MediumMedium+11nextjs.org+11Stack Overflow+11。
2. dynamic = 'force-dynamic' 不足以清缓存
虽然在 Handler 顶部写了 export const dynamic = 'force-dynamic',它只关闭“完整路由缓存”(Full Route Cache),但不影响数据缓存 nextjs.org+4Reddit+4Stack Overflow+4。
3. 缺少 fetchCache = 'force-no-store'
官方说明:需同时添加 export const fetchCache = 'force-no-store' 或 default-no-store,才能跳过 Data Cache,确保每次请求都刷新数据 nextjs.org+1Medium+1。
4. 注意斜杠跳转问题
访问 /api/chatsessions 会自动 308 跳转到 /api/chatsessions/。若前端和 Nginx 路径不一致,可能导致缓存配置失效。
解决方案
// app/api/chatsessions/route.ts
export const dynamic = 'force-dynamic';
export const fetchCache = 'force-no-store';
import { NextResponse } from "next/server";
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export async function GET() {
const client = await pool.connect();
try {
const { rows } = await client.query(`
SELECT id, created_at
FROM chats
ORDER BY created_at DESC
LIMIT 50
`);
const sessions = rows.map(r => ({ id: r.id, createdAt: r.created_at }));
return NextResponse.json(sessions, {
headers: {
'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'
}
});
} finally {
client.release();
}
}
dynamic = 'force-dynamic':禁用完整路由缓存fetchCache = 'force-no-store':禁用数据缓存,即 Data Cache- 在返回头中加入
Cache-Control: no-store:防止浏览器或代理缓存
辅助配置:Nginx 与前端请求
Nginx 配置:
location ^~ /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_cache off;
proxy_buffering off;
add_header Cache-Control "no-store, max-age=0" always;
}
前端 fetch 示例:
await fetch('/api/chatsessions/', { cache: 'no-store' });
确保 API 路径统一带斜杠,避免 308 重定向带来的缓存问题。
验证方法
- 修改数据库内容后,使用
curl -i https://.../api/chatsessions/查看响应头是否带Cache-Control: no-store。 - 访问接口并刷新页面,应立即获取最新数据。
总结
- Next.js Route Handler 默认仍使用数据缓存,需要配合使用
dynamic + fetchCache才能彻底关闭; - 保证 API 路径带斜杠,防止跳转时走代理缓存;
- 全链路禁缓存保障(路由层 + Handler + Nginx + 前端),即可实现“每次请求都实时更新”。
这篇记录了从问题定位到解决完整流程,希望能帮助遇到同样问题的同学。