Skip to content

Commit 9697bcd

Browse files
authored
Fix notFound status code with ISR in app (#55542)
This ensures we properly set/restore the status code with ISR paths in app router so that when we set the 404 status code with `notFound` it is persisted properly. Fixes: #43831 Closes: #48342 x-ref: #49387 (comment)
1 parent 0338dcd commit 9697bcd

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

packages/next/src/server/base-server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
22382238
html: result,
22392239
pageData: metadata.pageData,
22402240
headers,
2241+
status: isAppPath ? res.statusCode : undefined,
22412242
},
22422243
revalidate: metadata.revalidate,
22432244
}
@@ -2493,6 +2494,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {
24932494
)
24942495
}
24952496

2497+
if (cachedData.status) {
2498+
res.statusCode = cachedData.status
2499+
}
2500+
24962501
return {
24972502
type: isDataReq ? 'rsc' : 'html',
24982503
body: isDataReq

test/e2e/app-dir/app-static/app-static.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,10 @@ createNextDescribe(
700700
'variable-revalidate-edge/post-method-request/page_client-reference-manifest.js',
701701
'partial-gen-params-no-additional-lang/[lang]/[slug]/page_client-reference-manifest.js',
702702
'partial-gen-params-no-additional-slug/[lang]/[slug]/page_client-reference-manifest.js',
703+
'articles/[slug]/page.js',
704+
'articles/[slug]/page_client-reference-manifest.js',
705+
'articles/works.html',
706+
'articles/works.rsc',
703707
].sort()
704708
)
705709
})
@@ -752,6 +756,22 @@ createNextDescribe(
752756
"initialRevalidateSeconds": false,
753757
"srcRoute": "/",
754758
},
759+
"/articles/works": Object {
760+
"dataRoute": "/articles/works.rsc",
761+
"experimentalBypassFor": Array [
762+
Object {
763+
"key": "Next-Action",
764+
"type": "header",
765+
},
766+
Object {
767+
"key": "content-type",
768+
"type": "header",
769+
"value": "multipart/form-data",
770+
},
771+
],
772+
"initialRevalidateSeconds": 1,
773+
"srcRoute": "/articles/[slug]",
774+
},
755775
"/blog/seb": Object {
756776
"dataRoute": "/blog/seb.rsc",
757777
"experimentalBypassFor": Array [
@@ -1404,6 +1424,23 @@ createNextDescribe(
14041424
`)
14051425
expect(curManifest.dynamicRoutes).toMatchInlineSnapshot(`
14061426
Object {
1427+
"/articles/[slug]": Object {
1428+
"dataRoute": "/articles/[slug].rsc",
1429+
"dataRouteRegex": "^\\\\/articles\\\\/([^\\\\/]+?)\\\\.rsc$",
1430+
"experimentalBypassFor": Array [
1431+
Object {
1432+
"key": "Next-Action",
1433+
"type": "header",
1434+
},
1435+
Object {
1436+
"key": "content-type",
1437+
"type": "header",
1438+
"value": "multipart/form-data",
1439+
},
1440+
],
1441+
"fallback": null,
1442+
"routeRegex": "^\\\\/articles\\\\/([^\\\\/]+?)(?:\\\\/)?$",
1443+
},
14071444
"/blog/[author]": Object {
14081445
"dataRoute": "/blog/[author].rsc",
14091446
"dataRouteRegex": "^\\\\/blog\\\\/([^\\\\/]+?)\\\\.rsc$",
@@ -1590,6 +1627,15 @@ createNextDescribe(
15901627
})
15911628
}
15921629

1630+
it('should correctly handle statusCode with notFound + ISR', async () => {
1631+
for (let i = 0; i < 5; i++) {
1632+
const res = await next.fetch('/articles/non-existent')
1633+
expect(res.status).toBe(404)
1634+
expect(await res.text()).toContain('This page could not be found')
1635+
await waitFor(500)
1636+
}
1637+
})
1638+
15931639
it('should cache correctly for fetchCache = default-cache', async () => {
15941640
const res = await next.fetch('/default-cache')
15951641
expect(res.status).toBe(200)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { notFound } from 'next/navigation'
2+
3+
export interface Props {
4+
params: {
5+
slug: string
6+
}
7+
}
8+
9+
const Article = ({ params }: Props) => {
10+
const { slug } = params
11+
12+
if (slug !== 'works') {
13+
return notFound()
14+
}
15+
return <div>Articles page with slug</div>
16+
}
17+
18+
export const revalidate = 1
19+
export const dynamicParams = true
20+
21+
export async function generateStaticParams() {
22+
return [
23+
{
24+
slug: 'works', // Anything not this should be a 404 with no ISR
25+
},
26+
]
27+
}
28+
29+
export default Article

0 commit comments

Comments
 (0)