Skip to content

Commit 4ba1f06

Browse files
Lezzioijjk
andauthored
fix: status code to avoid navigation with empty props (vercel#60968)
### What? Currently, when a middleware is active and the path results in a 404, the server responds with a 200 status code to data requests. We propose a change to ensure that a 404 status code is returned in these situations, as expected, solving production issues for the navigation router. ### Why? The client data requests (identified with `_next/data` path & `x-nextjs-data` header) get answered the status code 200. The code below is executed when there is a version skew for the data requests (e.g prefetch in production). https://github.com/vercel/next.js/blob/4125069840ca98981f0e7796f55265af04f3e903/packages/next/src/server/lib/router-server.ts#L217-L227 The version skew consists in the client side version identified with the buildId in `__NEXT_DATA__ ` tag to be obsolete compared to the server version (`BUILD_ID` file). In the case of prefetching, this leads to the code above being executed, therefore the `prefetch-reducer.ts` handles the response as valid and sets it in its cache. Which ultimately triggers a navigation with empty prop, resulting in erroneous behaviours reported in issues and in our production websites: https://github.com/vercel/next.js/blob/4125069840ca98981f0e7796f55265af04f3e903/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.ts#L54-L74 By switching the response to a 404, we trigger this code in the fetch (`fetchServerResponse`). This change prompts a hard navigation (mpaNavigation), effectively refreshing the client version and resynching it with the server version. https://github.com/vercel/next.js/blob/4125069840ca98981f0e7796f55265af04f3e903/packages/next/src/client/components/router-reducer/fetch-server-response.ts#L125-L134 ### How? We simply update the status code to 404 here: https://github.com/vercel/next.js/blob/4125069840ca98981f0e7796f55265af04f3e903/packages/next/src/server/lib/router-server.ts#L223 Closes: vercel#60785 Closes: vercel#59295 Fixes: vercel#47516 --------- Co-authored-by: JJ Kasper <[email protected]>
1 parent bdd0dd2 commit 4ba1f06

File tree

3 files changed

+11
-26
lines changed

3 files changed

+11
-26
lines changed

packages/next/src/server/lib/router-server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export async function initialize(opts: {
180180
removePathPrefix(invokePath, config.basePath) === '/404'
181181
) {
182182
res.setHeader('x-nextjs-matched-path', parsedUrl.pathname || '')
183-
res.statusCode = 200
183+
res.statusCode = 404
184184
res.setHeader('content-type', 'application/json')
185185
res.end('{}')
186186
return null

packages/next/src/shared/lib/router/router.ts

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -323,30 +323,17 @@ async function withMiddlewareEffects<T extends FetchDataOutput>(
323323
return null
324324
}
325325

326-
try {
327-
const data = await options.fetchData()
326+
const data = await options.fetchData()
328327

329-
const effect = await getMiddlewareData(
330-
data.dataHref,
331-
data.response,
332-
options
333-
)
328+
const effect = await getMiddlewareData(data.dataHref, data.response, options)
334329

335-
return {
336-
dataHref: data.dataHref,
337-
json: data.json,
338-
response: data.response,
339-
text: data.text,
340-
cacheKey: data.cacheKey,
341-
effect,
342-
}
343-
} catch {
344-
/**
345-
* TODO: Revisit this in the future.
346-
* For now we will not consider middleware data errors to be fatal.
347-
* maybe we should revisit in the future.
348-
*/
349-
return null
330+
return {
331+
dataHref: data.dataHref,
332+
json: data.json,
333+
response: data.response,
334+
text: data.text,
335+
cacheKey: data.cacheKey,
336+
effect,
350337
}
351338
}
352339

@@ -2403,7 +2390,7 @@ export default class Router implements BaseRouter {
24032390
locale,
24042391
}),
24052392
hasMiddleware: true,
2406-
isServerRender: this.isSsr,
2393+
isServerRender: false,
24072394
parseJSON: true,
24082395
inflightCache: this.sdc,
24092396
persistCache: !this.isPreview,

test/e2e/middleware-general/test/index.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,12 @@ describe('Middleware Runtime', () => {
104104
function runTests({ i18n }: { i18n?: boolean }) {
105105
it('should work with notFound: true correctly', async () => {
106106
const browser = await next.browser('/ssr-page')
107-
await browser.eval('window.beforeNav = 1')
108107
await browser.eval('window.next.router.push("/ssg/not-found-1")')
109108

110109
await check(
111110
() => browser.eval('document.documentElement.innerHTML'),
112111
/This page could not be found/
113112
)
114-
expect(await browser.eval('window.beforeNav')).toBe(1)
115113

116114
await browser.refresh()
117115
await check(

0 commit comments

Comments
 (0)