当前位置: 首页 > news >正文

Next.js Route Handler 写 API:缓存、动态参数与流式返回全踩一遍

Next.js Route Handler 写 API:缓存、动态参数与流式返回全踩一遍

很多人从 Pages Router 的pages/api迁到 App Router 后,第一反应是「Route Handler 不就是换了个文件名吗」,结果上线才发现:GET 接口返回的数据死活不更新、动态路由参数取不到、想做 SSE 流式推送不知道怎么下手。这三个坑我都踩过,这篇把它们串起来讲清楚。

一个「不更新」的 GET 接口

先看最容易翻车的场景。你在app/api/now/route.ts写了个返回当前时间的接口:

// app/api/now/route.ts —— 错误示范exportasyncfunctionGET(){returnResponse.json({now:newDate().toISOString()})}

本地next dev一切正常,每次刷新时间都变。但next build && next start后,你会发现时间永远是构建那一刻,再刷新也不变。

原因:App Router 里 Route Handler 的 GET 默认会被静态化(相当于构建时执行一次,结果缓存下来)。这和 Pages Router 完全不同,是很多人踩的第一个坑。

修法有两种,按需求选:

// 方式一:显式声明这个路由不缓存exportconstdynamic='force-dynamic'exportasyncfunctionGET(){returnResponse.json({now:newDate().toISOString()})}
// 方式二:用 revalidate 做定时缓存(比如 60 秒更新一次)exportconstrevalidate=60exportasyncfunctionGET(){returnResponse.json({now:newDate().toISOString()})}

判断依据很简单:接口结果跟请求无关、可以缓存(如首页配置、商品列表)就用revalidate;每次都要最新(如当前用户、实时数据)就force-dynamic。另外,只要你在 handler 里读了requestheaderscookiessearchParams,Next.js 会自动把它标成动态,不用手动声明——但读new Date()这种「外部副作用」它是察觉不到的,所以才需要你显式标注。

动态参数:第二个参数别写错

带参数的路由,比如app/api/user/[id]/route.ts,新手常这么取参数:

// 错误:GET 的第一个参数是 Request,不是 paramsexportasyncfunctionGET(params){console.log(params.id)// undefined}

正确姿势是从第二个参数里解构params。注意 Next.js 15 起params变成了 Promise,要await:

// app/api/user/[id]/route.tsimport{NextRequest}from'next/server'exportasyncfunctionGET(req:NextRequest,{params}:{params:Promise<{id:string}>}){const{id}=awaitparams// Next.js 15 起需要 await// 查询字符串从 req.nextUrl 上取,别去 params 里找constverbose=req.nextUrl.searchParams.get('verbose')constuser=awaitgetUser(id)if(!user){// 返回 404 用状态码,不要返回 200 再塞个 error 字段returnResponse.json({error:'not found'},{status:404})}returnResponse.json(verbose?user:{id:user.id,name:user.name})}asyncfunctiongetUser(id:string){// 这里替换成你的真实查询return{id,name:'Alice',email:'a@x.com'}}

两个关键点:路径参数([id])从params拿,查询参数(?verbose=1)从req.nextUrl.searchParams拿,两者来源不同别搞混;返回错误时用真实 HTTP 状态码,别用「200 + error 字段」那套,前端res.ok才能正确判断。

流式返回:SSE 推送进度

最后是进阶场景。假设你有个耗时任务(比如调用大模型、批量处理),想边算边把进度推给前端,而不是让用户干等。这时候用ReadableStream做 Server-Sent Events:

// app/api/progress/route.tsexportconstdynamic='force-dynamic'// 流式接口一定不能被缓存exportasyncfunctionGET(){constencoder=newTextEncoder()conststream=newReadableStream({asyncstart(controller){for(leti=1;i<=5;i++){awaitnewPromise((r)=>setTimeout(r,500))// 模拟耗时步骤// SSE 格式:data: <内容>\n\n,两个换行是消息分隔符,少一个前端收不到constchunk=`data:${JSON.stringify({step:i,total:5})}\n\n`controller.enqueue(encoder.encode(chunk))}controller.close()// 忘了 close,前端连接会一直挂着},})returnnewResponse(stream,{headers:{'Content-Type':'text/event-stream','Cache-Control':'no-cache',Connection:'keep-alive',},})}

前端用原生EventSource接:

constes=newEventSource('/api/progress')es.onmessage=(e)=>{const{step,total}=JSON.parse(e.data)console.log(`进度${step}/${total}`)if(step===total)es.close()// 收完手动关,否则会自动重连}

这里最容易漏的两处:一是 SSE 每条消息必须以\n\n结尾,只写一个换行前端事件根本不触发;二是服务端controller.close()和客户端es.close()都要记得调,不然连接泄漏,部署到 serverless 平台还会一直计费。

小结

  • GET 默认静态化是 App Router 最大的行为差异:结果要实时就export const dynamic = 'force-dynamic',能缓存就export const revalidate = N
  • 动态路由参数在第二个参数的params里,Next.js 15 起要await;查询参数在req.nextUrl.searchParams,两者来源不同。
  • 流式返回用ReadableStream+text/event-stream,记住 SSE 消息以\n\n结尾、两端都要主动 close。

一句话记忆:App Router 的 Route Handler 默认是「静态优先」的,凡是要动态就得显式声明,这是它和 Pages Router 最本质的区别。

http://www.jsqmd.com/news/1255391/

相关文章:

  • 【北京经济管理职业学院、四川工商学院支持】第五届公共艺术与人文发展国际学术会议 (ICPAHD 2026)
  • 2026年台州GEO/SEO优化公司大盘点,本地网络优化服务商全面梳理 - 商业新知
  • 被端口占用逼疯后,我用AI从零写了个本地服务管理器
  • 2026 无锡梁溪黄金回收门店排行,行业易奢福稳居本地优选榜单 - 易奢福
  • 研学小小推荐官选拔投票如何制作?青少年研学活动微信投票零基础教程 - 微信投票小程序
  • Unity热更新实战:HybridCLR配置、原理与避坑指南
  • 如何轻松解锁网易云音乐限制:NCMconverter终极音频转换指南
  • 终极指南:5分钟掌握ncmdump免费解密网易云音乐NCM格式的完整教程
  • 基于YOLOv8的农作物智能识别系统开发与实践
  • AI工具助力专科生高效完成毕业论文写作
  • 2026 重庆闲置名牌包包变现实操攻略|易奢福多门店分布,正规回收 LV 香奈儿爱马仕 - 遁地的c
  • 2026厦门电气回收优质商家推荐,变频器回收,电控箱回收,接触器回收,配电柜回收,高压熔断器回收优质商家优选指南! - 品牌商讯
  • 沧州代理记账公司怎么选?先看专业度、政策熟悉度和交付标准 - 中国品牌企业推荐网
  • Java应用API版本管理与网关部署策略:2026年实践指南
  • C++实现摄影测量光束法平差:从共线方程到三维重建
  • CC3220MODx GPIO驱动强度与复位状态深度解析:物联网硬件设计避坑指南
  • 北京产业园入驻流程哪家服务省心:博亚信诚舒心 - 18102756859
  • 宿州防水补漏公司推荐:这几家正规靠谱机构合集(2026 年 7 月份实测) - 吉林同城获客
  • AI写作工具提升专著创作效率的五大核心方案
  • 终极碧蓝航线自动化工具:3步配置解放你的游戏时间
  • 普通散户与团队量化需求差在哪:从使用流程做分流
  • BetterGI:用AI解放双手的20+项原神自动化方案
  • Spotlight Attention:优化LLM推理的KV缓存哈希技术
  • 巴音郭楞博湖黄金奢侈品回收三大老牌机构实测对比|本地卖金完整避坑指南(2026 最新) - 华金汇黄金回收
  • 千笔与云笔AI:研究生论文写作工具对比分析
  • AI数字员工如何提升共享出行司机激活率37%
  • 2026 年 7 月最新调研|武汉在职研究生培训机构 TOP5 实测,本地考生择校指南 - 互联网科技品牌测评
  • 如何轻松提取Wallpaper Engine壁纸素材:RePKG终极使用指南
  • LangGraph中的Reducer是什么
  • 2026年英语听力学习机如何选?从泛听、精听到复述的完整路径 - 博客万