Skip to content

Commit f8f8e85

Browse files
authored
fix: handle absolute rewrite URLs (#1325)
* fix: relativise rewritten URLs * fix: handle external rewrites * chore: add demos
1 parent 10291d1 commit f8f8e85

File tree

6 files changed

+60
-2
lines changed

6 files changed

+60
-2
lines changed

demos/middleware/pages/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ export default function Home() {
1616
Welcome to <a href="https://nextjs.org">Next.js!</a>
1717
</h1>
1818

19-
<p><Link href="/shows/rewriteme">Rewrite me</Link></p>
19+
<p><Link href="/shows/rewriteme">Rewrite URL</Link></p>
20+
<p><Link href="/shows/rewrite-absolute">Rewrite to absolute URL</Link></p>
21+
<p><Link href="/shows/rewrite-external">Rewrite to external URL</Link></p>
2022
</main>
2123
</div>
2224
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NextResponse } from 'next/server'
2+
import { NextFetchEvent, NextRequest } from 'next/server'
3+
4+
export function middleware(req: NextRequest, ev: NextFetchEvent) {
5+
const res = NextResponse.rewrite(new URL('/shows/100', req.url))
6+
res.headers.set('x-modified-in-rewrite', 'true')
7+
return res
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const Show = () => {
2+
return (
3+
<div>
4+
<p>This should have been rewritten</p>
5+
</div>
6+
)
7+
}
8+
9+
export default Show
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NextResponse } from 'next/server'
2+
import { NextFetchEvent, NextRequest } from 'next/server'
3+
4+
export function middleware(req: NextRequest, ev: NextFetchEvent) {
5+
const res = NextResponse.rewrite('http://example.com/')
6+
res.headers.set('x-modified-in-rewrite', 'true')
7+
return res
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const Show = () => {
2+
return (
3+
<div>
4+
<p>This should have been rewritten</p>
5+
</div>
6+
)
7+
}
8+
9+
export default Show

plugin/src/templates/edge/utils.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ export interface FetchEventResult {
55
waitUntil: Promise<any>
66
}
77

8+
/**
9+
* This is how Next handles rewritten URLs.
10+
*/
11+
export function relativizeURL(url: string | string, base: string | URL) {
12+
const baseURL = typeof base === 'string' ? new URL(base) : base
13+
const relative = new URL(url, base)
14+
const origin = `${baseURL.protocol}//${baseURL.host}`
15+
return `${relative.protocol}//${relative.host}` === origin
16+
? relative.toString().replace(origin, '')
17+
: relative.toString()
18+
}
19+
20+
821
export const addMiddlewareHeaders = async (
922
originResponse: Promise<Response> | Response,
1023
middlewareResponse: Response,
@@ -14,7 +27,8 @@ export const addMiddlewareHeaders = async (
1427
return originResponse
1528
}
1629
// We need to await the response to get the origin headers, then we can add the ones from middleware.
17-
const response = await originResponse
30+
const res = await originResponse
31+
const response = new Response(res.body, res)
1832
middlewareResponse.headers.forEach((value, key) => {
1933
response.headers.set(key, value)
2034
})
@@ -33,6 +47,14 @@ export const buildResponse = async ({
3347
request.headers.set('x-nf-next-middleware', 'skip')
3448
const rewrite = res.headers.get('x-middleware-rewrite')
3549
if (rewrite) {
50+
const rewriteUrl = new URL(rewrite, request.url)
51+
const baseUrl = new URL(request.url)
52+
if(rewriteUrl.hostname !== baseUrl.hostname) {
53+
// Netlify Edge Functions don't support proxying to external domains, but Next middleware does
54+
const proxied = fetch(new Request(rewriteUrl.toString(), request))
55+
return addMiddlewareHeaders(proxied, res)
56+
}
57+
res.headers.set('x-middleware-rewrite', relativizeURL(rewrite, request.url))
3658
return addMiddlewareHeaders(context.rewrite(rewrite), res)
3759
}
3860
if (res.headers.get('x-middleware-next') === '1') {

0 commit comments

Comments
 (0)