From fc2dcb83543d88af9e0920b90a035652d6db5166 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Mon, 24 Mar 2025 14:23:37 +0000 Subject: [PATCH] fix(app): call renderer when routes don't match (#13483) * fix(app): call renderer when routes don't match * chore: pick 404 exactly * chore: pick route differently Co-authored-by: ascorbic <213306+ascorbic@users.noreply.github.com> --- .changeset/wet-bottles-invite.md | 5 +++++ packages/astro/src/core/app/index.ts | 10 +++++++++- .../middleware space/integration-middleware-post.js | 4 ++++ packages/astro/test/middleware.test.js | 12 ++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .changeset/wet-bottles-invite.md diff --git a/.changeset/wet-bottles-invite.md b/.changeset/wet-bottles-invite.md new file mode 100644 index 0000000000..629e3d3182 --- /dev/null +++ b/.changeset/wet-bottles-invite.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a bug where an Astro adapter couldn't call the middleware when there isn't a route that matches the incoming request. diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index 36560478ed..baf76a0268 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -7,6 +7,7 @@ import { REROUTE_DIRECTIVE_HEADER, clientAddressSymbol, responseSentSymbol, + DEFAULT_404_COMPONENT, } from '../constants.js'; import { getSetCookiesFromResponse } from '../cookies/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; @@ -88,7 +89,6 @@ export class App { #baseWithoutTrailingSlash: string; #pipeline: AppPipeline; #adapterLogger: AstroIntegrationLogger; - #renderOptionsDeprecationWarningShown = false; constructor(manifest: SSRManifest, streaming = true) { this.#manifest = manifest; @@ -331,6 +331,14 @@ export class App { this.#logger.debug('router', 'Astro matched the following route for ' + request.url); this.#logger.debug('router', 'RouteData:\n' + routeData); } + // At this point we haven't found a route that matches the request, so we create + // a "fake" 404 route, so we can call the RenderContext.render + // and hit the middleware, which might be able to return a correct Response. + if (!routeData) { + routeData = this.#manifestData.routes.find( + (route) => route.component === '404.astro' || route.component === DEFAULT_404_COMPONENT, + ); + } if (!routeData) { this.#logger.debug('router', "Astro hasn't found routes that match " + request.url); this.#logger.debug('router', "Here's the available routes:\n", this.#manifestData); diff --git a/packages/astro/test/fixtures/middleware space/integration-middleware-post.js b/packages/astro/test/fixtures/middleware space/integration-middleware-post.js index a4e0c90ad9..cb1855d481 100644 --- a/packages/astro/test/fixtures/middleware space/integration-middleware-post.js +++ b/packages/astro/test/fixtures/middleware space/integration-middleware-post.js @@ -8,6 +8,10 @@ export const onRequest = defineMiddleware((context, next) => { }, }); } + + if (context.url.pathname === '/does-not-exist') { + return context.rewrite('/rewrite'); + } return next(); }); diff --git a/packages/astro/test/middleware.test.js b/packages/astro/test/middleware.test.js index 75b9659320..199128ebdc 100644 --- a/packages/astro/test/middleware.test.js +++ b/packages/astro/test/middleware.test.js @@ -318,6 +318,18 @@ describe('Middleware API in PROD mode, SSR', () => { assert.equal(response.headers.get('content-type'), 'text/html'); }); + it('can render a page that does not exist', async () => { + const request = new Request('http://example.com/does-not-exist'); + const routeData = app.match(request); + + const response = await app.render(request, { routeData }); + assert.equal(response.status, 200); + const html = await response.text(); + const $ = cheerio.load(html); + assert.equal($('p').html(), null); + assert.equal($('span').html(), 'New content!!'); + }); + it('can set locals for prerendered pages to use', async () => { const text = await fixture.readFile('/client/prerendered/index.html'); assert.equal(text.includes('

yes they can!

'), true);