diff --git a/demos/middleware/pages/index.js b/demos/middleware/pages/index.js index 775f996a1e..b229d2bafd 100644 --- a/demos/middleware/pages/index.js +++ b/demos/middleware/pages/index.js @@ -16,7 +16,9 @@ export default function Home() { Welcome to Next.js! -

Rewrite me

+

Rewrite URL

+

Rewrite to absolute URL

+

Rewrite to external URL

) diff --git a/demos/middleware/pages/shows/rewrite-absolute/_middleware.ts b/demos/middleware/pages/shows/rewrite-absolute/_middleware.ts new file mode 100644 index 0000000000..6c7696a767 --- /dev/null +++ b/demos/middleware/pages/shows/rewrite-absolute/_middleware.ts @@ -0,0 +1,8 @@ +import { NextResponse } from 'next/server' +import { NextFetchEvent, NextRequest } from 'next/server' + +export function middleware(req: NextRequest, ev: NextFetchEvent) { + const res = NextResponse.rewrite(new URL('/shows/100', req.url)) + res.headers.set('x-modified-in-rewrite', 'true') + return res +} diff --git a/demos/middleware/pages/shows/rewrite-absolute/index.js b/demos/middleware/pages/shows/rewrite-absolute/index.js new file mode 100644 index 0000000000..871c824075 --- /dev/null +++ b/demos/middleware/pages/shows/rewrite-absolute/index.js @@ -0,0 +1,9 @@ +const Show = () => { + return ( +
+

This should have been rewritten

+
+ ) +} + +export default Show diff --git a/demos/middleware/pages/shows/rewrite-external/_middleware.ts b/demos/middleware/pages/shows/rewrite-external/_middleware.ts new file mode 100644 index 0000000000..1fdaeb8ec9 --- /dev/null +++ b/demos/middleware/pages/shows/rewrite-external/_middleware.ts @@ -0,0 +1,8 @@ +import { NextResponse } from 'next/server' +import { NextFetchEvent, NextRequest } from 'next/server' + +export function middleware(req: NextRequest, ev: NextFetchEvent) { + const res = NextResponse.rewrite('http://example.com/') + res.headers.set('x-modified-in-rewrite', 'true') + return res +} diff --git a/demos/middleware/pages/shows/rewrite-external/index.js b/demos/middleware/pages/shows/rewrite-external/index.js new file mode 100644 index 0000000000..871c824075 --- /dev/null +++ b/demos/middleware/pages/shows/rewrite-external/index.js @@ -0,0 +1,9 @@ +const Show = () => { + return ( +
+

This should have been rewritten

+
+ ) +} + +export default Show diff --git a/plugin/src/templates/edge/utils.ts b/plugin/src/templates/edge/utils.ts index e780e7684d..57230273f5 100644 --- a/plugin/src/templates/edge/utils.ts +++ b/plugin/src/templates/edge/utils.ts @@ -5,6 +5,19 @@ export interface FetchEventResult { waitUntil: Promise } +/** + * This is how Next handles rewritten URLs. + */ + export function relativizeURL(url: string | string, base: string | URL) { + const baseURL = typeof base === 'string' ? new URL(base) : base + const relative = new URL(url, base) + const origin = `${baseURL.protocol}//${baseURL.host}` + return `${relative.protocol}//${relative.host}` === origin + ? relative.toString().replace(origin, '') + : relative.toString() +} + + export const addMiddlewareHeaders = async ( originResponse: Promise | Response, middlewareResponse: Response, @@ -14,7 +27,8 @@ export const addMiddlewareHeaders = async ( return originResponse } // We need to await the response to get the origin headers, then we can add the ones from middleware. - const response = await originResponse + const res = await originResponse + const response = new Response(res.body, res) middlewareResponse.headers.forEach((value, key) => { response.headers.set(key, value) }) @@ -33,6 +47,14 @@ export const buildResponse = async ({ request.headers.set('x-nf-next-middleware', 'skip') const rewrite = res.headers.get('x-middleware-rewrite') if (rewrite) { + const rewriteUrl = new URL(rewrite, request.url) + const baseUrl = new URL(request.url) + if(rewriteUrl.hostname !== baseUrl.hostname) { + // Netlify Edge Functions don't support proxying to external domains, but Next middleware does + const proxied = fetch(new Request(rewriteUrl.toString(), request)) + return addMiddlewareHeaders(proxied, res) + } + res.headers.set('x-middleware-rewrite', relativizeURL(rewrite, request.url)) return addMiddlewareHeaders(context.rewrite(rewrite), res) } if (res.headers.get('x-middleware-next') === '1') {