diff --git a/.changeset/dirty-pianos-try.md b/.changeset/dirty-pianos-try.md new file mode 100644 index 000000000000..1a83f174870f --- /dev/null +++ b/.changeset/dirty-pianos-try.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: use 308 responses for trailing slash redirects, instead of 301s diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index 0707898dff72..13d89588adca 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -213,7 +213,7 @@ export async function respond(request, options, manifest, state) { if (normalized !== url.pathname && !state.prerendering?.fallback) { return new Response(undefined, { - status: 301, + status: 308, headers: { 'x-sveltekit-normalize': '1', location: diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index d50125ae8c7b..9921b6ef8653 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -1,3 +1,4 @@ +import * as http from 'node:http'; import { expect } from '@playwright/test'; import { test } from '../../../utils.js'; @@ -173,6 +174,16 @@ test.describe('env', () => { test.describe('trailingSlash', () => { test('adds trailing slash', async ({ baseURL, page, clicknav }) => { + // we can't use Playwright's `request` here, because it resolves redirects + const status = await new Promise((fulfil, reject) => { + const request = http.get(`${baseURL}/path-base/slash`); + request.on('error', reject); + request.on('response', (response) => { + fulfil(response.statusCode); + }); + }); + expect(status).toBe(308); + await page.goto('/path-base/slash'); expect(page.url()).toBe(`${baseURL}/path-base/slash/`);