diff --git a/packages/runtime/src/templates/edge-shared/utils.ts b/packages/runtime/src/templates/edge-shared/utils.ts index ce6772fb1a..56e8826c94 100644 --- a/packages/runtime/src/templates/edge-shared/utils.ts +++ b/packages/runtime/src/templates/edge-shared/utils.ts @@ -8,6 +8,22 @@ export interface FetchEventResult { type NextDataTransform = (data: T) => T +function normalizeDataUrl(redirect: string) { + // If the redirect is a data URL, we need to normalize it. + // next.js code reference: https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/get-next-pathname-info.ts#L46 + if (redirect.startsWith('/_next/data/') && redirect.includes('.json')) { + const paths = redirect + .replace(/^\/_next\/data\//, '') + .replace(/\.json/, '') + .split('/') + + const buildId = paths[0] + redirect = paths[1] !== 'index' ? `/${paths.slice(1).join('/')}` : '/' + } + + return redirect +} + /** * This is how Next handles rewritten URLs. */ @@ -249,6 +265,12 @@ export const buildResponse = async ({ res.headers.set('x-nextjs-redirect', relativizeURL(redirect, request.url)) } + const nextRedirect = res.headers.get('x-nextjs-redirect') + + if (nextRedirect && isDataReq) { + res.headers.set('x-nextjs-redirect', normalizeDataUrl(nextRedirect)) + } + if (res.headers.get('x-middleware-next') === '1') { return addMiddlewareHeaders(context.next(), res) } diff --git a/test/e2e/modified-tests/middleware-redirects/test/index.test.ts b/test/e2e/modified-tests/middleware-redirects/test/index.test.ts index f697ca4973..63a96b4d6e 100644 --- a/test/e2e/modified-tests/middleware-redirects/test/index.test.ts +++ b/test/e2e/modified-tests/middleware-redirects/test/index.test.ts @@ -37,14 +37,13 @@ describe('Middleware Redirect', () => { expect(res.headers.get('location')?.endsWith('/default/about')).toEqual(false) }) - usuallySkip(`should redirect to data urls with data requests and internal redirects`, async () => { + it(`should redirect to data urls with data requests and internal redirects`, async () => { const res = await fetchViaHTTP( next.url, `/_next/data/${next.buildId}/es/old-home.json`, { override: 'internal' }, { redirect: 'manual', headers: { 'x-nextjs-data': '1' } }, ) - expect(res.headers.get('x-nextjs-redirect')?.endsWith(`/es/new-home?override=internal`)).toEqual(true) expect(res.headers.get('location')).toEqual(null) })