Correct statusCode when visiting _error directly (#26610)

This fixes non-stop reloading when visiting `_error` directly in development caused by the `statusCode` being 200 unexpectedly while HMR returns the page as `invalid` which triggers `on-demand-entries` to reload the page. 

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

Fixes: https://github.com/vercel/next.js/issues/8036
x-ref: https://github.com/vercel/next.js/pull/8033
This commit is contained in:
JJ Kasper 2021-06-28 07:50:53 -05:00 committed by GitHub
parent ae0dbe5e2c
commit c2f0653bd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 37 deletions

View file

@ -1444,6 +1444,7 @@ export default class Server {
): Promise<string | null> {
const is404Page = pathname === '/404'
const is500Page = pathname === '/500'
const isErrorPage = pathname === '/_error'
const isLikeServerless =
typeof components.Component === 'object' &&
@ -1462,6 +1463,10 @@ export default class Server {
res.statusCode = 404
}
if (isErrorPage && res.statusCode === 200) {
res.statusCode = 404
}
// ensure correct status is set when visiting a status page
// directly e.g. /500
if (STATIC_STATUS_PAGES.includes(pathname)) {

View file

@ -25,46 +25,26 @@ describe('Client Navigation', () => {
context.server = await launchApp(join(__dirname, '../'), context.appPort, {
env: { __NEXT_TEST_WITH_DEVTOOL: 1 },
})
const prerender = [
'/async-props',
'/default-head',
'/empty-get-initial-props',
'/error',
'/finish-response',
'/head',
'/json',
'/link',
'/stateless',
'/fragment-syntax',
'/custom-extension',
'/styled-jsx',
'/styled-jsx-external',
'/with-cdm',
'/url-prop',
'/dynamic/ssr',
'/dynamic/[slug]/route',
'/nav',
'/nav/about',
'/nav/on-click',
'/nav/querystring',
'/nav/self-reload',
'/nav/hash-changes',
'/nav/shallow-routing',
'/nav/redirect',
'/nav/as-path',
'/nav/as-path-using-router',
'/nested-cdm',
]
await Promise.all(
prerender.map((route) => renderViaHTTP(context.appPort, route))
)
})
afterAll(() => killApp(context.server))
it('should not reload when visiting /_error directly', async () => {
const browser = await webdriver(context.appPort, '/_error')
await browser.eval('window.hello = true')
// wait on-demand-entries timeout since it can trigger
// reloading non-stop
for (let i = 0; i < 15; i++) {
expect(await browser.eval('window.hello')).toBe(true)
await waitFor(1000)
}
const html = await browser.eval('document.documentElement.innerHTML')
expect(html).toContain('This page could not be found')
expect(html).toContain('404')
})
describe('with <Link/>', () => {
it('should navigate the page', async () => {
const browser = await webdriver(context.appPort, '/nav')