Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .changeset/giant-areas-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'astro': major
---

Updates trailing slash behavior of endpoint URLs.

In Astro v5.0, custom endpoints whose URL ended in a file extension (e.g. `/src/pages/sitemap.xml.ts` ) could be accessed with a trailing slash (`/sitemap.xml/`) or without (`/sitemap.xml`), regardless of the value configured for `build.trailingSlash`.

In Astro v6.0, these endpoints can only be accessed without a trailing slash. This is true regardless of your `build.trailingSlash` configuration.

#### What should I do?

Review your links to your custom endpoints that include a file extension in the URL and remove any trailing slashes:

```diff
-<a href="/sitemap.xml/">Sitemap</a>
+<a href="/sitemap.xml">Sitemap</a>
```
3 changes: 1 addition & 2 deletions packages/astro/src/core/routing/manifest/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,11 @@ function createFileBasedRoutes(
}

// Get trailing slash rule for a path, based on the config and whether the path has an extension.
// TODO: in Astro 6, change endpoints with extentions to use 'never'
const trailingSlashForPath = (
pathname: string | null,
config: AstroConfig,
): AstroConfig['trailingSlash'] =>
pathname && hasFileExtension(pathname) ? 'ignore' : config.trailingSlash;
pathname && hasFileExtension(pathname) ? 'never' : config.trailingSlash;

function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): RouteData[] {
const { config } = settings;
Expand Down
7 changes: 4 additions & 3 deletions packages/astro/test/units/routing/trailing-slash.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,15 @@ describe('trailingSlash', () => {
assert.equal(json, '{"success":true}');
});

it('should match the API route when request has a trailing slash, with a file extension', async () => {
it('should NOT match the API route when request has a trailing slash, with a file extension', async () => {
const { req, res, text } = createRequestAndResponse({
method: 'GET',
url: '/dot.json/',
});
container.handle(req, res);
const json = await text();
assert.equal(json, '{"success":true}');
const html = await text();
assert.equal(html.includes(`<span class="statusMessage">Not found</span>`), true);
assert.equal(res.statusCode, 404);
});

it('should also match the API route when request lacks a trailing slash, with a file extension', async () => {
Expand Down
Loading