diff --git a/.changeset/empty-bottles-allow.md b/.changeset/empty-bottles-allow.md new file mode 100644 index 000000000000..1f6e63d09796 --- /dev/null +++ b/.changeset/empty-bottles-allow.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Return 404 status code for 404.astro in SSR diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index fc7aa80bb19b..fc03d333c6a6 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -82,6 +82,11 @@ export class App { } } + // Use the 404 status code for 404.astro components + if(routeData.route === '/404') { + defaultStatus = 404; + } + let mod = this.#manifest.pageMap.get(routeData.component)!; if (routeData.type === 'page') { diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts index 17d800b1d188..95e47a52ce1c 100644 --- a/packages/astro/src/core/app/node.ts +++ b/packages/astro/src/core/app/node.ts @@ -1,9 +1,10 @@ +import type { RouteData } from '../../@types/astro'; import type { SerializedSSRManifest, SSRManifest } from './types'; import * as fs from 'fs'; import { IncomingMessage } from 'http'; import { deserializeManifest } from './common.js'; -import { App } from './index.js'; +import { App, MatchOptions } from './index.js'; const clientAddressSymbol = Symbol.for('astro.clientAddress'); @@ -24,10 +25,10 @@ function createRequestFromNodeRequest(req: IncomingMessage, body?: Uint8Array): } export class NodeApp extends App { - match(req: IncomingMessage | Request) { - return super.match(req instanceof Request ? req : createRequestFromNodeRequest(req)); + match(req: IncomingMessage | Request, opts: MatchOptions = {}) { + return super.match(req instanceof Request ? req : createRequestFromNodeRequest(req), opts); } - render(req: IncomingMessage | Request) { + render(req: IncomingMessage | Request, routeData?: RouteData) { if ('on' in req) { let body = Buffer.from([]); let reqBodyComplete = new Promise((resolve, reject) => { @@ -43,10 +44,10 @@ export class NodeApp extends App { }); return reqBodyComplete.then(() => { - return super.render(req instanceof Request ? req : createRequestFromNodeRequest(req, body)); + return super.render(req instanceof Request ? req : createRequestFromNodeRequest(req, body), routeData); }); } - return super.render(req instanceof Request ? req : createRequestFromNodeRequest(req)); + return super.render(req instanceof Request ? req : createRequestFromNodeRequest(req), routeData); } } diff --git a/packages/astro/test/ssr-404-500-pages.test.js b/packages/astro/test/ssr-404-500-pages.test.js index 4f5f1f8cf9de..1cfc0098c68b 100644 --- a/packages/astro/test/ssr-404-500-pages.test.js +++ b/packages/astro/test/ssr-404-500-pages.test.js @@ -26,6 +26,17 @@ describe('404 and 500 pages', () => { expect($('h1').text()).to.equal('Something went horribly wrong!'); }); + it('404 page returned when a route does not match and passing routeData', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/some/fake/route'); + const routeData = app.match(request, { matchNotFound: true }); + const response = await app.render(request, routeData); + expect(response.status).to.equal(404); + const html = await response.text(); + const $ = cheerio.load(html); + expect($('h1').text()).to.equal('Something went horribly wrong!'); + }); + it('500 page returned when there is an error', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/causes-error'); diff --git a/packages/astro/test/test-adapter.js b/packages/astro/test/test-adapter.js index 297e117a24a6..2bfc0bff45b3 100644 --- a/packages/astro/test/test-adapter.js +++ b/packages/astro/test/test-adapter.js @@ -27,9 +27,9 @@ export default function ({ provideAddress } = { provideAddress: true }) { import { App } from 'astro/app'; class MyApp extends App { - render(request) { + render(request, routeData) { ${provideAddress ? `request[Symbol.for('astro.clientAddress')] = '0.0.0.0';` : ''} - return super.render(request); + return super.render(request, routeData); } }