Files
56d75a0b77 Fix invalid HTML response for route-level RSC requests in deployment adapter (#91541)
In a deployed environment, `onCacheEntryV2` determines whether a
postponed response is HTML-origin or RSC-origin by checking whether
meta.url ends with `.rsc`.

For some dynamic full-route RSC requests, Next was passing a URL with
query params into onCacheEntry, for example:
`/[tenant]/samples.rsc?nxtPtenant=tenant-x`

Because that string does not end with .rsc, `onCacheEntryV2`
misclassified the request as HTML and treated it as text/html instead of
an RSC response.

This PR normalizes the URL before passing it to `onCacheEntry`, so the
callback receives the pathname rather than the full URL-with-query.

---------

Co-authored-by: JJ Kasper <[email protected]>
2026-03-18 12:17:31 -07:00

64 lines
1.3 KiB
TypeScript

import { Suspense } from 'react'
import { cacheLife, cacheTag } from 'next/cache'
import { connection } from 'next/server'
async function CachedShell({ tenant }: { tenant: string }) {
'use cache'
cacheLife({
stale: 300,
revalidate: 300,
expire: 3600,
})
cacheTag(`sample-shell:${tenant}`)
return (
<>
<p id="cached-tenant">
Tenant: <strong>{tenant}</strong>
</p>
<p id="cached-at">
Cached shell token: <strong>{crypto.randomUUID()}</strong>
</p>
</>
)
}
async function DynamicRequestContent({
params,
}: {
params: Promise<{ tenant: string }>
}) {
const { tenant } = await params
await connection()
return (
<p id="dynamic">
Request-time content for <strong>{tenant}</strong>.
</p>
)
}
export default function SamplesPage({
params,
}: {
params: Promise<{ tenant: string }>
}) {
const shell = params.then(async ({ tenant }) => (
<CachedShell tenant={tenant} />
))
return (
<main>
<h1>Samples Route</h1>
<Suspense fallback={<p id="shell-fallback">Loading cached shell...</p>}>
{shell}
</Suspense>
<Suspense fallback={<p id="fallback">Loading request-time content...</p>}>
<DynamicRequestContent params={params} />
</Suspense>
</main>
)
}