cdn-caching
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVercel Caching
Vercel 缓存
You are an expert in understanding Vercel's caching infrastructure, and how the CDN Cache, ISR, and PPR work.
你是理解Vercel缓存基础设施以及CDN缓存、ISR和PPR工作原理的专家。
Core Knowledge
核心知识
- ISR (and PPR, a rendering strategy built on it) is a framework feature — Next.js, SvelteKit, Nuxt, and Astro all use it on Vercel, and the layers, metrics, and CLI here apply regardless. (For caching data between your function and a backend, that's the Runtime Cache — a separate layer; see References.)
- PPR (Partial Prerendering) — a rendering strategy, not a cache layer: the static shell lives in the ISR cache while a function renders the dynamic holes per request and streams them into the same response. A route with holes still invokes the function on a shell hit; a holeless route is just ISR (a pure HIT).
prerender
- ISR(以及基于它构建的渲染策略PPR)是一种框架特性——Next.js、SvelteKit、Nuxt和Astro在Vercel上均支持该特性,本文涉及的层级、指标和CLI工具均通用。(若要在函数与后端之间缓存数据,需使用Runtime Cache——这是一个独立的缓存层级;详见参考资料。)
- PPR(Partial Prerendering,部分预渲染)——是一种渲染策略,而非缓存层级:静态外壳存储在ISR缓存中,同时函数会针对每个请求渲染动态部分并将其流式传输到同一响应中。包含动态部分的路由在命中静态外壳时仍会调用函数;无动态部分的路由则完全等同于ISR(纯命中)。
prerender
How caching works
缓存工作原理
Vercel caches at multiple layers between the visitor and your backend. A request reaches the nearest PoP, which routes to a Vercel region; the CDN then checks each layer in order and returns a cached response as soon as one is available, so your function runs only when nothing upstream has a valid copy.
Vercel在访问者与后端之间设置了多层缓存机制。请求会先到达最近的PoP(边缘节点),再路由到Vercel区域;随后CDN会按顺序检查每个层级,一旦找到可用的缓存响应就立即返回,因此只有当上游所有缓存都没有有效副本时,才会运行你的函数。
Cache layers
缓存层级
- CDN cache — regional, ephemeral. On a hit the region returns the response with no function call. Reads/writes are free.
- ISR cache — durable, in a single Function region. On a CDN miss, Vercel reads here before invoking your function (cache shielding), then replicates the result back to the CDN. Survives deploys for 31 days or until revalidated; reads/writes are billed in 8 KB units.
- Function invocation — runs only if neither cache has a valid copy. It may read the Runtime/data cache (a separate layer; see References) and your backend, then Vercel stores the response in the ISR cache.
- Image cache — optimized images, cached on the CDN after the first transform.
- Purges propagate globally in ~300 ms.
Request collapsing: when many requests hit the same uncached path at once, Vercel collapses them into one function invocation per region to protect the origin.
- CDN缓存——区域级、临时缓存。命中时,区域节点无需调用函数即可直接返回响应。读写操作免费。
- ISR缓存——持久化缓存,存储在单个函数区域。当CDN缓存未命中时,Vercel会先读取ISR缓存(缓存屏蔽),再将结果同步回CDN缓存。该缓存可在部署后保留31天,或直到被重新验证;读写操作按8 KB单位计费。
- 函数调用——仅当CDN缓存和ISR缓存均无有效副本时才会触发。函数可能会读取Runtime/数据缓存(独立层级;详见参考资料)和后端数据,随后Vercel会将响应存储到ISR缓存中。
- 图片缓存——经过优化的图片,首次转换后会被缓存到CDN。
- 缓存清除操作会在约300毫秒内全局生效。
请求合并:当大量请求同时访问同一未缓存路径时,Vercel会将每个区域的请求合并为一次函数调用,以保护源站。
Key concepts
关键概念
-
Cache hit rate — share served from cache (/
HIT/STALE) versus origin (PRERENDER/MISS). Measure it over cacheable requests — excludeREVALIDATEDandBYPASS(redirects, errors, uncacheable methods), or they drag the ratio down for non-cache reasons. Low hit rate means more origin load and higher latency.(not set) -
Revalidation — refreshing cached content. Time-based runs automatically after an interval; on-demand runs when you call an API. Both use stale-while-revalidate: visitors keep getting the cached version while the new one regenerates in the background.
-
Invalidate vs. dangerously-delete — two ways to clear content, with very different blast on hit rate:
- Invalidate (, Next.js
invalidateByTag/revalidateTag) = stale-while-revalidate. Keeps serving stale while refreshing in the background → response showsrevalidatePath.x-vercel-cache: STALE - Dangerously-delete (, Next.js
dangerouslyDeleteByTagor a revalidate with no lifetime) = hard removal. The next request blocks in the foreground to regenerate →updateTag.x-vercel-cache: REVALIDATED
- Invalidate (
-
Cache tags & blast radius — tags group cached entries so one call can clear many. A coarse tag attached to thousands of paths has a large blast radius: a single write drops them all and the hit rate collapses until they re-warm. Prefer granular tags () plus a roll-up tag.
product-${id} -
Cache status / cache reason (response header):
x-vercel-cacheValue Meaning HITServed from cache; no function ran MISSNot cached; origin/function ran STALEServed stale while revalidating in background (SWR / invalidate) PRERENDERServed a prerendered ISR/PPR shell REVALIDATEDForeground revalidation after a delete (or )Pragma: no-cacheBYPASSCaching skipped ( ,no-store, cookies, etc.)private
-
缓存命中率——从缓存(/
HIT/STALE)提供服务的请求占比,与从源站(PRERENDER/MISS)提供服务的请求占比相对。需针对可缓存请求统计该指标——排除REVALIDATED和BYPASS(重定向、错误、不可缓存方法),否则这些非缓存原因会拉低命中率。命中率低意味着源站负载更高、延迟更大。(not set) -
重新验证——刷新缓存内容。基于时间的重新验证会在间隔时间后自动触发;按需重新验证会在调用API时触发。两者均采用stale-while-revalidate策略:访问者在后台生成新版本期间仍会获取缓存版本。
-
失效(Invalidate)与危险删除(dangerously-delete)——两种清除内容的方式,对命中率的影响截然不同:
- 失效(、Next.js的
invalidateByTag/revalidateTag)= stale-while-revalidate策略。在后台刷新期间仍提供过期内容 → 响应头显示revalidatePath。x-vercel-cache: STALE - 危险删除(、Next.js的
dangerouslyDeleteByTag或无生命周期的重新验证)= 强制删除。下一次请求会在前台阻塞以重新生成内容 →updateTag。x-vercel-cache: REVALIDATED
- 失效(
-
缓存标签与影响范围——标签用于对缓存条目进行分组,以便一次调用即可清除多个条目。若一个宽泛的标签关联了数千个路径,其影响范围会很大:一次写入操作会清除所有关联条目,命中率会在重新预热前骤降。建议优先使用细粒度标签(如),再搭配一个汇总标签。
product-${id} -
缓存状态/缓存原因(响应头):
x-vercel-cache取值 含义 HIT从缓存返回;未运行函数 MISS未命中缓存;运行了源站/函数 STALE返回过期内容,同时在后台重新验证(SWR/失效操作) PRERENDER返回预渲染的ISR/PPR静态外壳 REVALIDATED删除后进行前台重新验证(或 )Pragma: no-cacheBYPASS跳过缓存( 、no-store、Cookie等原因)private
Investigating cache issues
排查缓存问题
Reach for the Vercel CLI. gives aggregate numbers (requires Observability Plus); shows per-request behavior.
vercel metricsvercel logsMetrics need to be queried by team and project (). Filter production with (there is no flag). Run to discover dimensions; use for machine-readable output. With , remember is per time bucket — omit when you need totals across the whole window.
-S <team> -p <project>-f "environment eq 'production'"--prodvercel metrics schema <metric>-F json-g--limit-g指标需按团队和项目查询()。使用过滤生产环境数据(无参数)。运行可查看指标维度;使用可获取机器可读格式的输出。使用参数时,请注意**是按时间桶限制**——若需要整个时间窗口的总计数据,请省略。
-S <team> -p <project>-f "environment eq 'production'"--prodvercel metrics schema <metric>-F json-g--limit-gCache hit rate
缓存命中率
Start here for an overall picture of how well caching is working.
Step 1 — overall split. Group by . Treat , , and as cache-served; focus investigation on . Exclude and when computing a hit rate over cacheable traffic (see Debugging BYPASS traffic). means stale-while-revalidate is working — dig into revalidation frequency in Analyzing ISR costs, not here.
vercel.request.countcache_resultHITSTALEPRERENDERMISSBYPASS(not set)STALEbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production'" --group-by cache_result --since 24hStep 2 — where misses concentrate. Split the bucket (and optionally ) by , then by or :
MISSSTALEpath_typerouterequest_pathbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS'" \
--group-by path_type --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS' and path_type eq 'prerender'" \
--group-by request_path --since 24hWhat to expect: routes (static shells, ISR pages) should show a high share of /. A path with a disproportionate count is your short list for per-path header inspection ( above) and code review.
prerenderHITPRERENDERprerenderMISScurlstreaming_funcCache-ControlVaryprerender从整体缓存效果入手。
步骤1——整体拆分。按分组统计。将、和视为缓存命中;重点排查。计算可缓存流量的命中率时,需排除和(详见调试BYPASS流量)。意味着stale-while-revalidate策略正常工作——需在分析ISR成本中排查重新验证频率,而非此处。
cache_resultvercel.request.countHITSTALEPRERENDERMISSBYPASS(not set)STALEbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production'" --group-by cache_result --since 24h步骤2——未命中集中区域。将(可选包含)按拆分,再按或拆分:
MISSSTALEpath_typerouterequest_pathbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS'" \
--group-by path_type --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS' and path_type eq 'prerender'" \
--group-by request_path --since 24h预期结果:路由(静态外壳、ISR页面)应显示较高的/占比。若某个路径的占比过高,需优先对其进行路径头检查(上述命令)和代码审查。
prerenderHITPRERENDERprerenderMISScurlstreaming_funcCache-ControlVaryprerenderAnalyzing ISR costs
分析ISR成本
Once you know hit rate, quantify ISR spend and whether revalidation — not traffic volume — is driving it.
Utilization vs. ISR billing. Utilization is — total request volume. ISR cost is billed separately in 8 KB units: when the regional CDN misses and falls through to the ISR cache, and on every revalidation/regeneration. The regional CDN shields ISR heavily — most requests never touch the ISR layer, so read_units will be far below request count. Do not compare read_units to write_units as a utilization check; focus on write_units (revalidation cost) and how they relate to total traffic.
vercel.request.countread_unitswrite_unitsbash
vercel metrics vercel.request.count -S <team> -p <project> -a sum --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> -a sum --since 24hWhich routes revalidate most. Break write units down by and to find paths that regenerate often relative to traffic:
routerequest_pathbash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by route --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by request_path --since 24hRegeneration vs. serving. Group write units by — concentration in confirms revalidation (not per-request dynamic work) is the cost driver.
path_typebackground_funcTime-based vs. tag-based revalidation. Time-based intervals regenerate on a schedule whether or not content changed — often inefficient. Tag-based on-demand revalidation is usually better, but an overly broad tag has a large blast radius: one invalidate drops every entry that carries it.
- Tag blast radius — group write units by . If many unrelated routes show near-identical write counts, a shared hot tag is invalidating them in lockstep (e.g. every blog post rewriting at the same rate because they share one broad
cache_tagstag):blogPost
bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by cache_tags --since 24h- What triggered revalidation — group by
vercel.request.countto see which tags fire most often (triggering_tagis on request count only, not ISR operation metrics. It is one of the tags that triggered the page to be stale):triggering_tag
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "triggering_tag ne null" --group-by triggering_tag --since 24hTags with a large blast radius that revalidate frequently are the usual root cause of high write_units. Prefer granular tags () and on-demand invalidation over short time-based intervals for event-driven content.
product-${id}Confirm in code. Metrics tell you which tag is hot; the repo tells you why. Grep for the tag's invalidation call site — , , , — and read the trigger. A CMS webhook or a sync cron that invalidates a broad tag on every event (instead of a specific ) is the classic amplifier.
revalidateTag(invalidateByTag(updateTag(dangerouslyDeleteByTag(${type}:${id}了解命中率后,量化ISR支出,并确认是重新验证而非流量规模导致成本上升。
使用率与ISR计费。使用率即——总请求量。ISR成本按8 KB单位单独计费:当区域CDN未命中并回退到ISR缓存时产生,每次重新验证/重新生成时产生。区域CDN对ISR的屏蔽作用很强——大多数请求不会触及ISR层级,因此read_units会远低于请求量。不要将read_units与write_units对比来检查使用率;重点关注write_units(重新验证成本)及其与总流量的关系。
vercel.request.countread_unitswrite_unitsbash
vercel metrics vercel.request.count -S <team> -p <project> -a sum --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> -a sum --since 24h重新验证最频繁的路由。按和拆分write_units,找出相对于流量而言重新生成频率较高的路径:
routerequest_pathbash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by route --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by request_path --since 24h重新生成与服务。按分组统计write_units——若集中在,则确认是重新验证(而非单请求动态处理)导致成本上升。
path_typebackground_func基于时间与基于标签的重新验证。基于时间的间隔会按计划重新生成内容,无论内容是否变化——通常效率较低。基于标签的按需重新验证通常更优,但过于宽泛的标签会导致影响范围过大:一次失效操作会清除所有关联条目。
- 标签影响范围——按分组统计write_units。若许多不相关路由的write_units数量几乎相同,则说明存在一个共享的高频标签,导致它们同步失效(例如,所有博客文章因共享一个宽泛的
cache_tags标签而以相同频率重新生成):blogPost
bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by cache_tags --since 24h- 重新验证触发源——按分组统计
triggering_tag,查看哪些标签触发频率最高(vercel.request.count仅存在于请求计数指标中,不存在于ISR操作指标中,是导致页面过期的标签之一):triggering_tag
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "triggering_tag ne null" --group-by triggering_tag --since 24h影响范围大且重新验证频繁的标签通常是write_units过高的根本原因。对于事件驱动型内容,建议优先使用细粒度标签(如)和按需失效,而非短间隔的基于时间的重新验证。
product-${id}代码确认。指标会告诉你哪个标签是高频触发源,而代码仓库会告诉你原因。搜索该标签的失效调用位置——、、、——并查看触发逻辑。典型问题是CMS webhook或同步定时任务在每次事件时失效一个宽泛的标签(而非特定的),导致放大成本。
revalidateTag(invalidateByTag(updateTag(dangerouslyDeleteByTag(${type}:${id}Debugging BYPASS traffic
调试BYPASS流量
The largest legitimate sources of are Draft Mode and SEO crawlers. Draft Mode must bypass cache so editors see live content. SEO bots must receive the full response — especially on PPR routes where the static shell and dynamic holes are assembled at request time — so crawlers index what users actually see. That BYPASS is expected, not a misconfiguration.
BYPASSBefore tuning headers or revalidate intervals, confirm what's left after those two buckets:
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by bot_category --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by user_agent --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by request_method --since 24hThe Firewall/WAF with the skill can be used to manage verified SEO crawlers, block abusive bots, and rate-limit junk traffic before it distorts your hit-rate picture.
vercel-firewallBYPASS在调整头信息或重新验证间隔之前,先确认排除这两类流量后的剩余情况:
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by bot_category --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by user_agent --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by request_method --since 24h搭配技能的防火墙/WAF可用于管理已验证的SEO爬虫、阻止恶意机器人,并在垃圾流量影响命中率之前对其进行限流。
vercel-firewallReducing ISR cost
降低ISR成本
- Prefer tag-based over time-based revalidation. Replace short intervals with on-demand
revalidate/revalidateTagwhen content changes — time-based regeneration runs whether or not anything changed. If using Cache Components, analyzeinvalidateByTagcalls with thecacheLifeskill.next-cache-components - Scope tags to specific IDs. Invalidate , not a generic
blogPost:<id>/blogPosttag — one broad invalidate regenerates everything that carries it.page - Tune the revalidate interval where your framework declares it (Next.js /
revalidate, SvelteKitcacheLife, Nuxtisr, Astro). For Next.js Cache Components, see therouteRulesskill.next-cache-components - Use headers to cache dynamic functions.
CDN-Cache-Control
- 优先使用基于标签的重新验证。将短间隔的替换为内容变化时的按需
revalidate/revalidateTag——基于时间的重新生成无论内容是否变化都会运行。若使用Cache Components,请使用invalidateByTag技能分析next-cache-components调用。cacheLife - 将标签限定到特定ID。失效,而非通用的
blogPost:<id>/blogPost标签——一次宽泛的失效操作会重新生成所有关联条目。page - 在框架声明处调整重新验证间隔(Next.js的/
revalidate、SvelteKit的cacheLife、Nuxt的isr、Astro的对应配置)。对于Next.js Cache Components,请查看routeRules技能。next-cache-components - 使用头缓存动态函数。
CDN-Cache-Control
Inspect one path
检查单个路径
bash
curl -sSI https://<host>/<path> | grep -iE 'x-vercel-cache|x-matched-path|cache-control|vary|age|set-cookie'This zero-dependency first reach shows the status (), the cache directives ( / / ), and — crucially — , which reveals rewrites like that expose experiment/flag precomputation. flags personalization (RSC, cookies); forces . For a per-phase timing breakdown, (CLI v48.9.0+; needs the tool installed) adds latency stats. A path that should cache but shows / usually has , , , a per-request input (cookies/headers/), or an uncacheable method (see FAQ).
x-vercel-cacheCache-ControlCDN-Cache-ControlVercel-CDN-Cache-Controlx-matched-path/precomputed/exp~.../...varyset-cookieBYPASSvercel httpstat /some/pathhttpstatMISSBYPASSprivateno-storemax-age=0searchParamsInspect one request. When metrics or headers give you a request ID, pull the full log record:
bash
vercel logs --request-id <request-id> --jsonUse so the agent can parse cache status, path, and timing fields programmatically.
--jsonbash
curl -sSI https://<host>/<path> | grep -iE 'x-vercel-cache|x-matched-path|cache-control|vary|age|set-cookie'这个零依赖的方法可查看缓存状态()、缓存指令(//),以及至关重要的****——它会显示重写路径(如),暴露实验/特性标志的预计算逻辑。标志表示个性化内容(RSC、Cookie);会强制触发。如需查看各阶段的时间 breakdown,(CLI v48.9.0+;需安装工具)可添加延迟统计。若某个应该缓存的路径显示/,通常是因为设置了、、、单请求输入(Cookie/头信息/)或不可缓存方法(详见FAQ)。
x-vercel-cacheCache-ControlCDN-Cache-ControlVercel-CDN-Cache-Controlx-matched-path/precomputed/exp~.../...varyset-cookieBYPASSvercel httpstat /some/pathhttpstatMISSBYPASSprivateno-storemax-age=0searchParams检查单个请求。当指标或头信息提供请求ID时,可拉取完整日志记录:
bash
vercel logs --request-id <request-id> --json使用参数可让工具程序解析缓存状态、路径和时间字段。
--jsonFAQ
FAQ
- What are prerender variant misses? When a route uses a dynamic param, each distinct cache-key variant is prerendered and cached separately, so each variant misses on its first hit per region and low-traffic ones rarely stay warm. The most common modern cause is feature-flag / experiment precomputation — middleware picks a variant per request (paths), and flags × routes × PPR segments multiply into thousands of ISR entries (also a middleware-invocation cost). Fix: collapse the variant matrix (retire finished experiments), or accept the cost.
/precomputed/exp~.../... - Does PPR avoid function invocations? No — a PPR route has dynamic holes by definition, so the cached shell hit still runs the function to fill them. (A route with no holes is just ISR and serves a pure HIT — see Key concepts.)
prerender - Why are there more function invocations than PPR requests? PPR requests have a static shell and a dynamic function invocation. When the static shell needs to be regenerated, it incurs a function invocation on top of the dynamic function for the content.
- 什么是预渲染变体未命中?当路由使用动态参数时,每个不同的缓存键变体都会被预渲染并单独缓存,因此每个变体在每个区域的首次请求都会未命中,低流量变体很难保持预热状态。最常见的现代原因是特性标志/实验预计算——中间件会针对每个请求选择一个变体(路径),标志×路由×PPR片段会生成数千个ISR条目(同时也会增加中间件调用成本)。修复方案:合并变体矩阵(结束已完成的实验),或接受该成本。
/precomputed/exp~.../... - **PPR是否能避免函数调用?**不能——PPR路由本质上包含动态部分,因此命中静态外壳后仍会运行函数来填充动态内容。(无动态部分的路由完全等同于ISR,会返回纯命中——详见关键概念。)
prerender - **为什么函数调用次数多于PPR请求次数?**PPR请求包含静态外壳和动态函数调用。当静态外壳需要重新生成时,除了内容的动态函数调用外,还会额外触发一次函数调用。
Related skills
相关技能
- — manage verified SEO crawlers, block abusive bots, and rate-limit junk BYPASS traffic.
vercel-firewall - — caching data between your function and a backend (per-region key-value / data cache). A different layer from the CDN/ISR caches; use it to cache an API response or query result inside a function.
runtime-cache - — Next.js
next-cache-components,use cache,cacheLife, andcacheTagtuning (one framework's ISR/PPR controls).revalidate
- ——管理已验证的SEO爬虫、阻止恶意机器人,并对垃圾BYPASS流量进行限流。
vercel-firewall - ——在函数与后端之间缓存数据(区域级键值/数据缓存)。这是与CDN/ISR缓存不同的层级;可用于在函数内部缓存API响应或查询结果。
runtime-cache - ——Next.js的
next-cache-components、use cache、cacheLife和cacheTag调优(某一框架的ISR/PPR控制)。revalidate
References:
参考资料:
- Caching overview: https://vercel.com/docs/caching
- ISR: https://vercel.com/docs/incremental-static-regeneration
- Partial Prerendering (PPR): https://vercel.com/docs/partial-prerendering
- Cache-Control headers: https://vercel.com/docs/caching/cache-control-headers
- Diagnosing and fixing cache issues (full runbook): https://vercel.com/docs/caching/cdn-cache/debug-cache-issues
- vercel metrics CLI: https://vercel.com/docs/cli/metrics
- vercel logs CLI: https://vercel.com/docs/cli/logs
- 缓存概述: https://vercel.com/docs/caching
- ISR: https://vercel.com/docs/incremental-static-regeneration
- Partial Prerendering (PPR): https://vercel.com/docs/partial-prerendering
- Cache-Control头信息: https://vercel.com/docs/caching/cache-control-headers
- 缓存问题诊断与修复(完整手册): https://vercel.com/docs/caching/cdn-cache/debug-cache-issues
- vercel metrics CLI: https://vercel.com/docs/cli/metrics
- vercel logs CLI: https://vercel.com/docs/cli/logs